二、真正的协变和逆变
概念:
1、以前的泛型系统(或者说没有in/out关键字时),是不能“变”的,无论是“逆”还是“顺(协)”。
2、当前仅支持接口和委托的逆变与协变 ,不支持类和方法。但数组也有协变性。
3、值类型不参与逆变与协变。
协变:Foo<ParentClass> = Foo<ChildClass>
public class TestOut<T> where T : new()
{
/*
* 关键字out因为协变的类型T只能作为输出参数使用,而不能作为输入参数
*/
//*****[协变]泛型委托Demo*****
//1、创建泛型委托
public delegate T MyFunA<T>(); //默认不支持协变与逆变
public delegate T MyFunB<out T>(); //设置支持协变
//public delegate void MyFunC<out T>(T param);//错误,协变类型只能“出”不能“入”(只能作为输出的返回类型,不能作为输入的参数类型!)
//2、创建委托变量
public MyFunA<object> FunAObject = null;
public MyFunA<string> FunAString = null;
public MyFunB<object> FunBObject = null;
public MyFunB<string> FunBString = null;
public MyFunB<int> FunBInt = null;
//3、验证结果
public void TestFun()
{
//FunAObject = FunAString;//错误,不可用协变
FunBObject = FunBString;//正确,可用协变可以完成子类string到父类object的转换
//FunBObject = FunBInt; //错误,值类型不参与协变
}
//*****[协变]泛型接口Demo*****
//1、创建泛型接口
public interface IMyInterfaceA<T> { } //默认不支持协变与逆变
public interface IMyInterfaceB<out T> { } //设置支持协变
//public interface IMyInterfaceC<out T>
//{
// void Test(T param);//错误,协变只能“出”不能“入”
//}
//2、创建接口变量
public IMyInterfaceA<object> interAObject = null;
public IMyInterfaceA<string> interAString = null;
public IMyInterfaceB<object> interBObject = null;
public IMyInterfaceB<string> interBString = null;
public IMyInterfaceB<int> interBInt = null;
//3、验证结果
public void TestInterface()
{
//interAObject = interAString; //错误,不可用协变
interBObject = interBString; //正确,可用协变可以完成子类string到父类object的转换
//interBObject = interBInt; //错误,值类型不参与协变
}
}
逆变:Foo<ChildClass> = Foo<ParentClass>
public class TestIn<T> where T : new() { /* * 关键字in因为逆变的类型只能作为输入参数,而不能作为输出参数 */ //*****[逆变]泛型委托***** //1、创建泛型委托 public delegate void MyActionA<T>(T param); //默认不支持协变与逆变 public delegate void MyActionB<in T>(T param); //设置支持逆变 //public delegate T MyActionC<in T>();//错误,逆变只能“入”不能“出”(只能作为输入的参数类型,不能作为输出的返回类型!)
//2、创建委托变量 public MyActionA<object> ActionAObject = null; public MyActionA<string> ActionAString = null; public MyActionB<object> ActionBObject = null; public MyActionB<string> ActionBString = null; public MyActionB<int> ActionBInt = null; //3、验证结果 public void TestAction() { //ActionAString = ActionAObject; //错误,不可用逆变 ActionBString = ActionBObject; //正确,可用逆变可以完成从父类object到子类string的转换 //ActionBInt = ActionBObject; //错误,值类型不参与逆变 } //*****[逆变]泛型接口***** //1、创建泛型接口 public interface IMyInterfaceA<T> { } //默认不支持协变与逆变 public interface IMyInterfaceB<in T> { } //设置支持逆变 //public interface IMyInterfaceC<in T> //{ // T Test();//错误,逆变只能“入”不能“出” //} //2、创建接口变量 public IMyInterfaceA<object> interAObject = null; public IMyInterfaceA<string> interAString = null; public IMyInterfaceB<object> interBObject = null; public IMyInterfaceB<string> interBString = null; public IMyInterfaceB<int> interBInt = null; //3、验证结果 public void TestInterface() { //interAString = interAObject; //错误,不可用逆变 interBString = interBObject; //正确,可用你变可以完成从父类object到子类string的转换 //interBInt = interBObject; //错误,值类型不参与逆变 } }