里氏代换原则不变性

The Liskov substitution principle Invariance

任何人都可以向我解释为什么这段代码不起作用吗?与 LSP 规则有何关系?在这种情况下,不变性是什么意思?

示例来自 Adaptive code via C# 书:

class Program
{
    static void Main(string[] args)
    {
        IDictionary<A, A> dict1 = new Dictionary<B,B>();
        IDictionary<B,B> dict2 = new Dictionary<A, A>();    
    }
}
public class A { }
public class B: A { }

错误信息

Error CS0266 Cannot implicitly convert type 'System.Collections.Generic.Dictionary<LSP.core.B, LSP.core.B>' to 'System.Collections.Generic.IDictionary<LSP.core.A, LSP.core.A>'. An explicit conversion exists (are you missing a cast?)
Error CS0266 Cannot implicitly convert type 'System.Collections.Generic.Dictionary<LSP.core.A, LSP.core.A>' to 'System.Collections.Generic.IDictionary<LSP.core.B, LSP.core.B>'. An explicit conversion exists (are you missing a cast?)

一个简单的例子:

class A { }
class B : A { }
class C : A { }

// Imagine this was allowed:
var dict1 = new Dictionary<B, B>();
IDictionary<A, A> dict2 = dict1;

// Then you did this:
var c = new C();
dict2[c] = c;

// And finally tried to do this:
B b = dict1.Keys.First(); // Breaks type safety, because First() returns a C instance

这是因为 IDictionary 是 generic class.

举个例子:

public class A { }
public class B: A { }

B 是 A 的子class,所以这是允许的。

A varName = new B();

但是当您在代码中使用 varName 时,您只能访问 A class

的属性

但是 List<B> 不是 List<A> 的子class,即使 BA 的子class。
编译器不检查继承的泛型参数类型,并认为它们是不同的类型。

不允许以下内容

List<A> listName = new List<B>();

允许什么id使用LSP规则来填充列表

List<A> listName = new List<A>();
ListName.Add(new B());

但是当您访问 ListName[0] 时,编译器会将您将获得的对象视为类型 A 对象。