Skip to main content
 首页 » 编程设计

c#之通用集合 C# 中的协方差

2024年01月13日32zhwl

我有一些类和接口(interface)

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>只允许您迭代集合,这就是它可以标记为协变的原因。