泛型集合 C# 中的协方差
本文关键字:方差 集合 泛型 | 更新日期: 2023-09-27 18:36:22
我有一些类和接口
public interface IGeoObject
{
GeoCoordinate GetGeocoordinate();
}
public class User : IGeoObject
{
public GeoCoordinate GetGeocoordinate()
{
//...
return GeoCoordinate;
}
}
public class Venue : IGeoObject
{
public GeoCoordinate GetGeocoordinate()
{
//...
return GeoCoordinate;
}
}
public class Place : IGeoObject
{
public GeoCoordinate GetGeocoordinate()
{
//...
return GeoCoordinate;
}
}
我有类型为 List<User>
的示例变量用户
我有签名的方法
double GetMinDistance(List<IGeoObject> objects, GeoCoordinate position)
我无法将用户传递给GetMinDistance
,因为泛型类型的协方差不起作用。
我可以创建其他列表并使用方法.ConvertAll
(或.CasT<T>
):
List<IGeoObject> list = new List<User>(listUser).ConvertAll(x => (IGeoObject)x);
var dist = GeoTest.GetMinDistance(list, position);
我不确定这是最优雅的解决方案。最尴尬的是调用方必须执行此转换。
这类似于我在架构中的问题?还有更优雅的解决方案吗?
附言说来话长,但我真的无法给出所有类别中同一物种的坐标。
那是因为List<T>
不是协变的。
public class List<T> : IList<T>, ICollection<T>,
IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>,
IEnumerable
如您所见,类声明中没有out
关键字。
您必须改用IEnumerable<T>
才能获得协方差支持。
public interface IEnumerable<out T> : IEnumerable
这是因为List<T>
有一组方法可以修改集合,并且使用协方差时,您将失去这些操作的编译类型安全性。 IEnumerable<T>
只允许您循环访问集合,这就是它可以标记为协变的原因。
您可以将签名更改为:
double GetMinDistance<TGeoObject>(List<TGeoObject> objects, GeoCoordinate position)
where TGeoObject : IGeoObject
{
// ...
}
您可以
定义显式(强制转换)或隐式运算符,用于获取List<User>
并将其转换为List<IGeoObject>
。
public static explicit operator List<IGeoObject>(List<IGeoObject> ls)
{
return new ls.ConvertAll(x => (IGeoObject)x);
}