Skip to main content
 首页 » 编程设计

c#之如何将通用集合转换为通用祖先集合

2024年01月13日33qlqwjy

考虑 Label 列表:

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

现在我想将其转换为 Controls 的集合:

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

我会尝试调用:

ScaleControls(labels); 

但这不能编译。

ScaleControls((ICollection<Control>)labels); 

编译,但在运行时崩溃。

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

编译,但在运行时崩溃。

有没有办法传递对象的通用列表?


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

public class ControlList : Collection<Control> 
{ 
} 
 
pubic void InvalidateControls(ControlList controls) 
{ 
} 

但这意味着必须改造所有使用泛型的代码。

请您参考如下方法:

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

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

你的问题是 ICollection<T>不是协变的。 ICollection 不是协变的原因是为了防止像这样的方法是邪恶的:

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

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

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

List<Control>有一个采用 IEnumerable<Control> 的构造函数.为什么我们可以通过labels在?因为IEnumerable<T>是协变的:你不能将任何东西放入 IEnumerable<T> ;你只能把东西拿出来。因此,您知道您可以处理从 IEnumerable<T> 中检索到的任何内容作为 T(当然)或其任何基本类型。

编辑

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

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); 
}