为什么协方差不适用于泛型方法

问题描述 投票:0回答:2

假设我有接口和类:

public interface ITree {}
public class Tree : ITree {}

由于

IEnumerable<T>
协变,所以下面的代码行编译成功:

IEnumerable<ITree> trees = new List<Tree>();

但是当我将它放入泛型方法中时:

public void Do<T>() where T : ITree
{
     IEnumerable<ITree> trees = new List<T>();
}

我从编译器中得到编译错误:

错误1无法将类型“System.Collections.Generic.List”隐式转换为“System.Collections.Generic.IEnumerable”。存在显式转换(是否缺少转换?) D:\lab\Lab.General\Lab.General\Program.cs 83 40 Lab.General

为什么协方差在这种情况下不起作用?

c# c#-4.0 covariance contravariance
2个回答
34
投票

这是因为方差仅适用于引用类型(类、接口和委托)。添加一个类约束,它就可以正常编译了:

public static void Do<T>() where T : class, ITree

0
投票

我只是想添加更多示例: 您可以调用

MakeDesignWhereTIsReference
并将
VehicleStruct
传递为
T
。但问题是:

引用类型支持协变和逆变,但值类型不支持它们。来自MS 文档

所以我们还需要限制

T
为引用类型;这可以借助
class
关键字来完成,该关键字添加了我们需要的限制。

public static class TestCovariance
{
    public static void MakeDesignWhereTIsReference<T>()
        where T : class, IVehicle // pay attention to class restriction
    {
        ICollection<IDesign<IVehicle>> list = new List<IDesign<IVehicle>>();
        var design = new Design<T>();
        list.Add(design);
    }

    public static void MakeDesignWhereTIsStruct<T>()
        where T : struct, IVehicle //This method will throw a cast exception
    {
        ICollection<IDesign<IVehicle>> list = new List<IDesign<IVehicle>>();
        var design = new Design<T>();
        list.Add((IDesign<IVehicle>)design);
    }
} 

public struct VehicleStruct : IVehicle { }

TestCovariance.MakeDesignWhereTIsReference<Ship>();
TestCovariance.MakeDesignWhereTIsStruct<VehicleStruct>();
© www.soinside.com 2019 - 2024. All rights reserved.