Liskov Substitution Principle Violations
Liskov Substitution Princple Common Smells
Variance in C¶
Starting from C# 4, generic interfaces allow variance though special keywords "in" and "out". Generic classes at the same time don't allow variance.
The "out" keyword guarantees that inside the implementation of that interface, a generic parameter can only be used in the return statments.
interface IPoppable<out T< { T Pop(); }
Compiles and absolutely correct:
var dogs = new Stack<Dog>();
dogs.Push(new Dog());
IPoppable<Animal> animals = dogs; // allowed
The "in" keyword guarantees that inside the implementation of that interface, a generic parameter can only be used as the input.
interface IPushable<in T> { void Push(T val); }
Compiles and absolutely correct:
IPushable<Animal> animals = new Stack<Animal>();
IPushable<Cat> cats = animals; // allowed
cats.Push(new Cat());
Downcasts is a smell¶
void PayBonus(Person p)
{
Customer c = (Customer)p; // downcast
// or
if (p is Person) {
Customer c = (Customer)p;
}
}
## Downcasts are not always the smell
Downcasts are allowed if we're absolutely sure about the type you're about to
downcast to.
```csharp
public void PayCashBack(int customerId, decimal amount)
{
Customer c = repository.GetCustomer(customerId);
var pv = c as PrivilegedCustomer;
if (pc != null {
pc.AddMoneyToAccount(amount);
}
else {
throw new ArgumentException("PayCashback on a regular customer");
}
}