有没有办法让泛型方法尊重 C# 中的协变?

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

如果我有这些类型:

public interface IVehicle { }

public class Ship : IVehicle { }

public interface IDesign<out T> where T : IVehicle { }

public class Design<T> : IDesign<T> where T : IVehicle { }

那么这个方法就可以正常工作了:

void MakeDesign1()
{
    ICollection<IDesign<IVehicle>> list = new List<IDesign<IVehicle>>();
    var design = new Design<Ship>();
    list.Add(design);
}

但是通用版本不会:

void MakeDesign2<T>()
    where T : IVehicle
{
    ICollection<IDesign<IVehicle>> list = new List<IDesign<IVehicle>>();
    var design = new Design<T>();
    list.Add(design);
}

我遇到编译错误

错误 CS1503 参数 1:无法从

Design<T>
转换为
IDesign<IVehicle>

这是为什么呢?

IDesign<T>
的类型参数被限制为
IVehicle
,并且它是协变的,所以任何
Design<T>
肯定都是
IDesign<Vehicle>

有没有办法解决这个问题,而不创建一个虚拟的

IDesign
接口,而没有
IDesign<T>
的类型参数来继承?我以前就这样做过,但是当涉及到像
Design<T>
这样的具体类型中定义方法时,它变得非常混乱!奇怪的事情,比如合并泛型方法会导致错误......

c# generics covariance
1个回答
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 caset 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.