C#返回类型协方差和Liskov替换原理

我正在尝试理解协方差和LSP。 从这个问题我可以看出C#不支持返回类型协方差。 然而Liskov替换原则对返回类型强加协方差。

这是否意味着在C#中应用这个原则是不可能的? 还是我想念一些东西?

C#仍然可以应用Liskov替换原则。

考虑:

public class Base1 { } public class Derived1 : Base1 { } public class Base2 { public virtual Base1 Method() { return new Base1(); } } public class Derived2 : Base2 { public override Base1 Method() { return new Derived1(); } } 

如果C#支持协变返回类型,那么Base2 Method()的覆盖可以这样声明:

 public class Derived2 : Base2 { public override Derived1 Method() { return new Derived1(); } } 

C#不允许这样做,并且必须声明返回类型与基类中的返回类型相同,即Base1

但是,这样做并不违反Liskov替代原则。

考虑一下:

 Base2 test = new Base2(); Base1 item = test.Method(); 

相比:

 Base2 test = new Derived2(); Base1 item = test.Method(); 

我们完全能够用new Derived2()替换new Base2() new Derived2()而没有任何问题。 这符合Liskov替代原则。

由于C#不支持返回类型协方差,因此在返回类型协方差时不可能违反Liskov原则。

好的消息来源是关于C#中SOLID原则的讨论: https : //youtu.be/gwIS9cZlrhk?t = 1886

C#通过generics和outgenerics修饰符确实对此function提供了有限的支持。 (参见: https : //docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-generic-modifier )

支持是有限的,因为它只适用于接口。 要重写接受的答案:

 public class Base1 { } public class Derived1 : Base1 { } public interface Base2 where T : Base1 { T Method(); } public class Derived2 : Base2 { public Derived1 Method() { return new Derived1(); } } 

在这种情况下, Derived2不仅会实现Base2 ,还会实现Base2

该原则生效,因为如果通过Base2接口调用Method ,它将具有Base1返回类型,但如果通过Derived2调用它,则它将具有Derived1返回类型。

类似地,您可以使用in generic修饰符实现参数逆转: https : //docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-generic-modifier

注意,不可能违反原则。 如果在上面的示例中将out关键字更改为in关键字,则源代码将无法编译,您将收到以下错误:

 Error CS1961 Invalid variance: The type parameter 'T' must be covariantly valid on 'Base2.Method()'. 'T' is contravariant.