如果我有这两个类:

class A {}
class B : A {}

我制作了一个List <!> lt; A <!> gt;但我想添加一个List <!> lt; B <!> gt;通过调用List <!> lt; A <!> gt; .AddRange(List <!> lt; B <!> gt;)但编译器拒绝:

Argument '1': cannot convert from 'System.Collections.Generic.List<A>'
to 'System.Collections.Generic.IEnumerable<B>

我完全理解,因为IEnumerable <!> lt; B <!> gt;不从IEnumerable <!> lt; A <!> gt;继承,其泛型类型具有继承。

我的解决方案是枚举List <!> lt; B <!> gt;并单独添加项目,因为List <!> lt; A <!> gt; .Add(A item)将与B项一起使用:

foreach(B item in listOfBItems)
{
    listOfAItems.Add(item);
}

然而,这是非表达性的,因为我想要的只是AddRange。

我可以用

List<B>.ConvertAll<A>(delegate(B item) {return (A)item;});

但这是不必要的错综复杂和用词不当因为我没有转换,我正在施展。

问题:如果我要编写自己的类似List的集合,我会添加哪种方法,这样我就可以将B的集合复制到A的集合中作为单行类似于List <!> lt; A <!> gt; .AddRange(List <!> lt; B <!> gt;)保留最大类型安全性。 (并且最大值我的意思是该参数既是集合又是类型的inhertance检查。)

有帮助吗?

解决方案

事实上,通用类型现在不是变体。在C#4.0中,IEnumerable <B <!> gt;将可转换为IEnumerable <A <!> gt; 如果B可通过参考转换转换为A 。有关此功能设计的一些详细信息,请参阅:

http://blogs.msdn.com/ ericlippert /存档/标签/协方差+和+逆变/ Default.aspx的

其他提示

这确实无法正常工作,因为.net中的泛型不支持协方差。

然而,你可以制作一个小帮手方法或类来克服这个问题。

如果您实现自己的列表类,则可以使用其他通用参数添加协方差:

class MyList<T> {
    void AddRange<U>(IEnumerable<U> items) where U: T {
        foreach (U item in items) {
            Add(item);
        }
    }
}

你不能这样做:

listOfAItems.AddRange(listOfBItems.Cast<A>());

我能够使用LINQ ...

实现这一目标
listOfAItems.AddRange(listOfBItems.Cast<A>());

如果您发现自己处于泛型类型不变的情况下,以下扩展方法可以让您的生活更轻松:

public static void AddRange<TList,TOther>(this List<TList> list, IEnumerable<TOther> collection) where TOther: TList {
    foreach(TOther e in collection) {
        list.Add(e);
    }
}

使用它作为扩展方法,而不必从List<T>派生或在某个实用程序类中使用此方法,而不是简化使用。您也可以从推理中获益,因此这个以前无效的调用将在没有任何修改的情况下生效:

List<Animal> animals;
List<Dog> dogs;
animals.AddRange(dogs);

我唯一能想到的就是这个

public class MyList<T> : List<T>
{
    public void AddRange<Tother>(IEnumerable<Tother> col)
        where Tother: T
    {    
        foreach (Tother item in col)
        {
            this.Add(item);
        }
    }
}

调用它意味着执行MyList <!> lt; A <!> gt; .AddRange <!> lt; B <!> gt;(MyList <!> lt; B <!> gt;)。如果参数不可枚举或者类型继承不能解决,那么它就会失败,因此它满足了我的问题的最大类型安全要求。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top