using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CSGDemo
{
//https://docs.microsoft.com/zh-cn/dotnet/standard/generics/covariance-and-contravariance
//#csg015-01
//术语:协变与逆变
//协变/Covariance:
//使你能够使用比原始指定的类型派生程度更大的类型。比如,你可以将 IEnumerable<Derived> 的实例分配给 IEnumerable<Base> 类型的变量。
//协变的类型参数使用 out 关键字声明
//逆变/Contravariance:
//使你能够使用比原始指定的类型更泛型(派生程度更小)的类型。比如,你可以将 Action<Base> 的实例分配给 Action<Derived> 类型的变量。
//逆变的类型参数使用 int 关键字声明
//只有接口和委托中的泛型类型参数可以使用in 和 out
public class DemoCode
{
//#csg015-02
//一个泛型接口的协变例子,IList<T> 中的 T 是协变类型参数
public void CovarianceInterface()
{
IEnumerable<Derived> d = new List<Derived>();
//你可以将【派生类的泛型类型】的实例赋值给【基类的泛型类型】的变量
IEnumerable<Base> b = d;
}
//#csg015-03
//一个泛型委托的协变例子,Func<TResult> 中的 TResult 是协变类型参数
public void CovarianceDelegate()
{
Func<Derived> fd = () => new Derived();
//你可以将【派生类的泛型类型】的实例赋值给【基类的泛型类型】的变量
Func<Base> fb = fd;
}
//#csg015-04
//一个泛型接口的逆变例子,IComparer<T> 中的 T 是逆变类型参数
public void ContravarianceInterface()
{
IComparable<Base> b = new DemoComparable<Base>();
//你可以将【基类泛型类型】的实例赋值给【派生类泛型类型】的变量
IComparable<Derived> d = b;
}
//#csg015-05
//一个泛型委托的逆变例子, Action<T> 中的 T 是逆变类型参数
public void ContravarianceDelegate()
{
Action<Base> b = (x) => Console.WriteLine(x);
//你可以将【基类泛型类型】的实例赋值给【派生类泛型类型】的变量
Action<Base> d = b;
}
//#csg015-06
//除了逆变和协变,泛型类型参数也可以是不可变(Invariance)的,比如 List<T>
//表示变量只能赋值为使用最初的类型的实例。 固定泛型类型参数既不是协变,也不是逆变。
public void Invariance()
{
List<Base> b = new List<Base>();
//List<Derived> d = b; //该行代码报 CS0029 错误。
}
//#csg015-07
//还有一种情况,Variant
//一个泛型类型可以同时包含协变和逆变的类型参数, Func<T,TResult> 中的 T 是逆变类型参数,而 TResult 是协变类型参数
public void Variant()
{
//逆变和协变在同一个类中的混合使用
Func<Base, Derived> func = (b) => new Derived();
Func<Derived, Base> func2 = func;
}
}
public class Base { }
public class Derived : Base { }
public class DemoComparable<T> : IComparable<T>
{
public int CompareTo(T? other)
{
throw new NotImplementedException();
}
}
}