You can't decide whether some code violates the LSP by the code itself. You need to know the contract that each method is to fulfill.
In the example, there is no explicit contract given, so we have to guess what the intended contract of the
Close() method might be.
Looking at the base class implementation of te Close() method, the only effect of that method is, that afterwards the
Status.Closed. My best guess of a contract for this method reads:
Do whatever is necessary to make the
But that's just a plausible guess. Nobody can be sure about that if it isn't explicitly written down.
Let's take my guess for granted.
Does the overridden
Close() method also fulfill that contract? There are two possibilities that after running this method we have
- We already had
Status.Closed before calling the method.
- We had
Status.Started. Then we call the base implementation, setting the field to
- In all other cases we end up with a different status.
Status only has the two possible values
Started (e.g. a 2-value enum), everything is fine, there's no LSP violation, because we always get
Status.Closed after the
But probably there are more possible
Status values, ending up in a
Status not being
Status.Closed, thus violating the contract.
The OP asked about the famous sentence "wherever I am using the base class, its derived class can be used".
So I'd like to elaborate on that.
I read it as "wherever I am using the base class within its contract, its derived class can be used, without violating that contract.
So it's not only about not producing compile errors or running without throwing errors, it's about doing what the contract demands.
And it only applies to situations where I ask the class to do something that's within its intended range of operations. So we need not care about abuse situations (e.g. where preconditions aren't met).
After re-reading your question, I think I should add a paragraph on polymorphism in that context.
Polymorphism means that for instances of different classes, the same method call results in different implementations being run. So polymorphism technically allows you to override our
Close() method with one that instead e.g. opens a stream. Technically, that's possible, but it's a bad use of polymorphism. And one principle about good and bad uses of polymorphism is the LSP.