协变和逆变
概念
协变:使用比原始指定的派生类型的派生程度更大(更具体的)的类型
逆变:使用比原始指定的派生类型的派生程度更小(不太具体的)的类型
协变和逆变能够实现数组类型、委托类型和泛型类型参数的隐式引用转换
协变
假如定义个基类Base,子类:Derived
协变会保留分配兼容性。相当于Base = Derived。
对比上边的概念:使用比原始指定的派生类型(Base)的派生程度更大的类型(Derived)
如:
1 2
| IEnumerable<string> strings = new List<string>(); IEnumerable<object> objects = strings;
|
基类为object,子类为string。
使用比原始指定的派生类型(object)的派生程度更大的类型(string)。换种理解方法,IEnumerable即:父类出现的地方,子类都可以进行替换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| namespace HelloWorld { class Program { static void Main(string[] args) { ICustomCovariant<object> o = new CustomCovariant<string>(); } }
public interface ICustomCovariant<out T> { T Get(); }
public class CustomCovariant<T> :ICustomCovariant<T> { public T Get() { return default(T); } }
}
|
逆变
逆变不保留分配兼容性。相当于Derived = Base;
对比上边的概念:使用比原始指定的派生类型(Derived)的派生程度更小的类型(Base)
如:
1 2 3
| static void SetObject(object o){} Action<object> actObject = SetObject; Action<string> actString = actObject;
|
基类为object,子类为string
使用比原始指定的派生类型(string)的派生程度更小的类型(object)。
换种理解方法:
Action 需要的string类型,但是指定一个object给他。 这样是不兼容的,因为有些string的方法则无法进行使用了,相当于子类的一些方法无法使用了,所以说是不兼容的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| namespace HelloWorld { class Program { static void Main(string[] args) { IContravariant<string> 0 = new CustomContravariant<object>(); } }
public interface IContravariant<in T> { void Get(T t); }
public class CustomContravariant<T> : IContravariant<T> { public void Get(T t) {
} } }
|
参考
https://learn.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/covariance-contravariance/
https://blog.51cto.com/u_15296378/4907653