如何将泛型集合转换为泛型集合的祖先? [英] How to cast a generic collection to an generic collection of ancestors?

查看:158
本文介绍了如何将泛型集合转换为泛型集合的祖先?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

列表标签

 集合< Label> labels = new Collection< Label>(); 

现在我想将它转换为 Controls $ b $ pre $ public void ScaleControls(ICollection< Control> controls){}

我会尝试调用:

  ScaleControls标签); 

但不能编译。

  ScaleControls((ICollection的<控制>)标签); 

编译,但在运行时崩溃。

 的ICollection<控制> controls =(ICollection< Control>)标签; 
ScaleControls(c);

编译,但在运行时崩溃。

有没有办法绕过通用的对象列表?






另一种方法是放弃通用列表,并使用typed列表:

  public class ControlList:Collection< Control> 
{
}

pubic void InvalidateControls(ControlList控件)
{
}

但是,这意味着所有使用泛型的代码都必须进行改进。

解决方案

你不能施放它;您必须自己转换它。

  InvalidateControls(新列表< Control>(labels)); // C#4或更高版本

您的问题在于 ICollection< T> 不是协变的。 ICollection不协变的原因是为了防止像这样的方法变得邪恶:
$ b $ pre $ void AddControl(ICollection< Control> controls,Control控制)
{
controls.Add(control);
}

为什么会是邪恶的?因为如果ICollection是协变的,该方法将允许您将TextBox添加到标签列表中:

  AddControl(new List< Label> (),new TextBox()); 

List< Control> 需要 IEnumerable< Control> 。为什么我们可以将标签传递给?因为 IEnumerable< T> 是协变的:你不能将任何东西放到 IEnumerable< T> 你只能把东西拿出来。因此,您知道可以将任何从 IEnumerable< T> 中检索到的任何东西视为T(当然)或其任何基类型
$ b

编辑



我刚刚注意到您正在使用.Net 3.5。在这种情况下, IEnumerable< T> 不是协变的,您需要更多代码才能转换集合。像这样:

  ICollection< T> ConvertCollection< T,U>(ICollection< U> collection)其中U:T 
{
var result = new List< T>(collection.Count);
foreach(集合中的var项)
result.Add(item);
}


Consider a list of Label:

Collection<Label> labels = new Collection<Label>();

Now i want to cast this to a collection of Controls:

public void ScaleControls(ICollection<Control> controls) {}

i would try calling:

ScaleControls(labels);

but that doesn't compile.

ScaleControls((ICollection<Control>)labels);

compiles, but crashes at runtime.

ICollection<Control> controls = (ICollection<Control>)labels;
ScaleControls(c);

compiles, but crashes at runtime.

Is there a way to pass around generic lists of objects?


The alternative is to abandon generic lists, and use typed lists:

public class ControlList : Collection<Control>
{
}

pubic void InvalidateControls(ControlList controls)
{
}

But that means all code using generics must be retrofitted.

解决方案

You can't cast it; you have to convert it yourself.

InvalidateControls(new List<Control>(labels));  //C# 4 or later

Your problem here is that ICollection<T> is not covariant. The reason ICollection is not covariant is to prevent methods like this from being evil:

void AddControl(ICollection<Control> controls, Control control)
{
    controls.Add(control);
}

Why would that be evil? Because if ICollection were covariant, the method would allow you to add TextBoxes to lists of labels:

AddControl(new List<Label>(), new TextBox());

List<Control> has a constructor that takes IEnumerable<Control>. Why can we pass labels in? Because IEnumerable<T> is covariant: You can't put anything into an IEnumerable<T>; you can only take things out. Because of that, you know that you can treat anything retrieved from the IEnumerable<T> as a T (of course) or any of its base types.

EDIT

I just noticed that you're using .Net 3.5. In that case, IEnumerable<T> is not covariant, and you'll need more code to convert the collection. Something like this:

ICollection<T> ConvertCollection<T, U>(ICollection<U> collection) where U : T
{
    var result = new List<T>(collection.Count);
    foreach (var item in collection)
        result.Add(item);
}

这篇关于如何将泛型集合转换为泛型集合的祖先?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆