Я искал признаки в коде, которые могли бы сказать, что принцип подстановки Лискова может быть потенциально нарушен. Сначала я сделал простой класс и еще один класс, унаследованный от него:
public class Adder
{
public virtual int Add(int operand1, int operand2)
{
return operand1 + operand2;
}
}
public class AdvancedAdder : Adder
{
}
Затем я создал UnitTest, обнаруживающий нарушение LSP:
public abstract class AdderUnitTestsBase
{
protected static Adder Adder;
[DataTestMethod]
[DataRow(2, 2, 4)]
[DataRow(-1, 2, 1)]
[DataRow(2, -3, -1)]
[DataRow(0, 0, 0)]
public void Add_ReturnsCorrectResult(
int operand1, int operand2, int result)
{
Assert.AreEqual(result, Adder.Add(operand1, operand2));
}
}
[TestClass]
public class AdderUnitTests : AdderUnitTestsBase
{
[ClassInitialize]
public static void ClassInit(TestContext context)
{
Adder = new Adder();
}
}
[TestClass]
public class AdvancedAdderUnitTests : AdderUnitTestsBase
{
[ClassInitialize]
public static void ClassInit(TestContext context)
{
Adder = new AdvancedAdder();
}
}
Затем я пробовал разные вещи, такие как изменение типа параметров или изменение количества параметров:
public class AdvancedAdder : Adder
{
public int Add(int operand1, int operand2, int operand3)
{
return operand1 + operand2 + operand3;
}
public uint Add(uint operand1, uint operand2)
{
return operand1 + operand2;
}
}
Это не нарушило LSP, потому что методы имеют разные сигнатуры. Это просто расширенный функционал. Единственное, что сработало, это использование ключевого слова «переопределить»:
public class AdvancedAdder : Adder
{
public override int Add(int operand1, int operand2)
{
return operand1 - operand2;
}
}
Похоже, что если я избегаю "переопределения" в C#, мне не нужно беспокоиться о возможном нарушении принципа подстановки Лискова. Как вы думаете, это правильно?