泛型协变与逆变

https://www.cnblogs.com/springsnow/p/11652915.html#_label2

10分钟浅谈泛型协变与逆变 - 王柏成 - 博客园 (cnblogs.com)

C#4.0泛型的协变,逆变深入剖析 - 心出发 - 博客园 (cnblogs.com)

协变和逆变体现在泛型接口和委托上面,也就是对泛型参数的声明,可以声明为协变,或者逆变。 如果有了参数的声明,则该泛型接口或者委托称为“变体”。

  • “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型。
  • “逆变”则是指能够使用派生程度更小的类型。逆变,逆于常规的变。

协变和逆变,使用“out”,和“in”两个关键字。但是只能用在接口和委托上面,对泛型的类型进行声明。

协变

当类型参数声明为“out”时,代表它是用来返回的,只能作为结果返回,中途不能更改。

class Class1 { void Main() { ITest<Animal> customerList1 = new Test<Animal>(); ITest<Animal> customerList2 = new Test<Bird>();//这也是能编译的,在泛型中,子类指向父类,我们称为协变 //Net4.0中已有的实现 IEnumerable<Animal> list = new List<Bird>(); } }

/// <summary> /// 动物 /// </summary> public class Animal { public int Id { get; set; } }

/// <summary> ////// </summary> public class Bird : Animal { public string Name { get; set; } } /// <summary> /// 接口参数 out 协变, 只能是返回结果 /// </summary> /// <typeparam name="T"></typeparam> public interface ITest<out T> { //属性只能有 get 访问器 T Attr1 { get; } T Get(); // void Show(T t);//方法中T不能作为传入参数 } /// <summary> /// 注意:类没有协变逆变 /// </summary> /// <typeparam name="T"></typeparam> public class Test<T> : ITest<T> { public T Attr1 { get { return default(T); } } public T Get() { return default(T); } public void Show(T t) { } }

逆变

当类型参数声明为"in"时,代表它是用来输入的,只能作为参数输入,不能被返回。

class Class1
{
    void Main()
    {
        ITest<Bird> customerList1 = new Test<Bird>();
        ITest<Bird> customerList2 = new Test<Animal>();//父类指向子类,我们称为逆变(强制转换)

        //Net4.0中已有的实现
        Action<Bird> act = new Action<Animal>((Animal i) => { });
        act(new Bird());


    }
}

/// <summary>
/// 动物
/// </summary>
public class Animal
{
    public int Id { get; set; }
}

/// <summary>
////// </summary>
public class Bird : Animal
{
    public string Name { get; set; }
}

/// <summary>
/// 逆变
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ITest<in T>
{
    //T Get();//不能作为返回值
    void Show(T t);
}

public class Test<T> : ITest<T>
{
    public T Get()
    {
        return default(T);
    }

    public void Show(T t)
    {
        Console.Write(typeof(T).Name);
    }
}
原文地址:https://www.cnblogs.com/springsnow/p/15201608.html