Search code examples
c#.netoopsolid-principlesliskov-substitution-principle

Does Array.Add method violates LSP?


Array class implements IList interface that has Add member. Array.Add invocation throws NotSupportedException. Is it a violation of The Liskov Substitution Principle or The Interface Segregation Principle or both of them?


Solution

  • This is definitely a violation of the interface segregation principle. ISP states that components should only depend on interfaces that they actually require. Array implements IList, but clearly does not need or want all of the methods defined by IList, because it chooses to throw an exception to explain that it doesn't support Add. Furthermore, anything that needs an Array now has an IList despite not needing all of its methods (because anything that wants an array is clearly not worried about Add, since it doesn't work anyway). Not supporting an operation that your interface suggests that you implement is clearly an ISP violation; forcing consuming code to depend on an interface despite not needing all of it is also an ISP violation.

    This can lead to a violation of the Liskov substitution principle. If code depends on an IList, LSP states that it should function correctly when passed any implementation of IList. However, when passed an Array, that code will now throw an exception any time it tries to call Add.

    Whether this constitutes an LSP violation depends how you see exceptions with respect to LSP. If you approach it from the viewpoint that the exceptions are a part of the expected contract, then it's fine. The method conforms to its contract, and any code that calls Add without accounting for the possibility of an exception is at fault for not doing so.

    If you're more of the opinion that NotSupportedException is considered an error or failing, then it's a clear LSP violation. Personally, I find that the SOLID principles support each other and are harder to address in a vacuum, so using the interface segregation principle as backup, I'd say that the interface says "I can do these things", so saying "actually, I can't do that thing" is an error, and therefore probably shouldn't be considered part of a valid contract. If the exception isn't part of the contract, then by throwing one, Array is violating Add's contract, and is therefore breaking LSP.