如果我有这些类型:
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>
这样的具体类型中定义方法时,它变得非常混乱!奇怪的事情,比如合并泛型方法会导致错误......
我相信为什么协方差不适用于通用方法包含正确的答案。但只想添加更多示例: 您可以调用
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>();