通用类型的集合

如果我有一个generics类:

public class MyClass { public T Value; } 

我想实例化几个项目,如…

 new MyClass new MyClass 

…并将它们添加到集合中。 如何定义集合以便它可以包含generics类型列表? 然后我想在某个时刻迭代集合,并使用Value属性。 可能?

让您的generics类inheritance自非generics基类,或实现非generics接口。 然后,您可以拥有此类型的集合,并在您用于访问集合内容的任何代码中进行强制转换。

这是一个例子。

 public abstract class MyClass { public abstract Type Type { get; } } public class MyClass : MyClass { public override Type Type { get { return typeof(T); } } public T Value { get; set; } } // VERY basic illustration of how you might construct a collection // of MyClass objects. public class MyClassCollection { private Dictionary _dictionary; public MyClassCollection() { _dictionary = new Dictionary(); } public void Put(MyClass item) { _dictionary[typeof(T)] = item; } public MyClass Get() { return _dictionary[typeof(T)] as MyClass; } } 

我能想到的唯一方法就是如下(包含在Console应用程序中进行测试):

 class Program { static void Main(string[] args) { var x = new MyClass() { Value = "34" }; var y = new MyClass() { Value = 3 }; var list = new List(); list.Add(x); list.Add(y); foreach (var item in list) { Console.WriteLine(item.GetValue); } } private interface IMyClass { object GetValue { get; } } private class MyClass : IMyClass { public T Value; public object GetValue { get { return Value; } } } } 

即,让MyClass实现一个空接口,然后将您的集合创建为一个包含实现该接口的类实例的集合。

更新:我在界面中添加了一个“GetValue”方法,允许您以对象的forms访问MyClass实例的“值”。 如果你想拥有一个包含混合类型的集合,这就像它将要获得的那样好。

您需要为MyClass定义基类,然后您的集合将是基类列表。 例如:

 void Main() { var a = new MyClass(); var b = new MyClass(); var c = new List(); c.Add(a); c.Add(b); } public class MyBase { } // Define other methods and classes here public class MyClass : MyBase { public T Value { get; set;} } 

我的大多数generics类型都有“Untyped”成员的接口:

 private interface IMyClass { object UntypedValue { get; } } private class MyClass : IMyClass { T Value { get; set; } object UntypedValue { get { return Value; } } } 

您也可以通过使用显式接口实现来实现此目的,但在我看来,使用单独的名称会更容易。 (还有一些关于显式接口实现的CA提示)

您希望拥有一个MyClass集合,其中每个实例中类型参数T的值都不同。 这在.NET中是不可能的; 它缺少Java通配符(?)的等价物。 你需要做的是创建一个非generics的基类或接口,MyClass可以实现它。 例如:

 public interface IMyClass { object Value { get; set; } } public class MyClass : IMyClass { public T Value { get; set; } object IMyClass.Value { get { return Value; } set { Value = (T)value; } } } List m = new List { new MyClass(), new MyClass }; 

我认为这里的问题是generics类实际上根本不是同一类型。 它们只是在编译时创建全新类型的模板(如果我理解正确的话)。 因此,根据运行时, MyClassMyClass完全不同的类型。 它们可能也是MyIntClassMyStringClass ,你显然不能在同一个列表中没有先装箱。 它们(必然)不inheritance相同的基类,实现相同的接口或其他任何东西。 它们和其他两种类型一样不同,你必须这样对待它们(即使你认为你知道的更好)。

当然,您可以让它们实现接口,inheritance基础对象或已经给出的任何其他选项。 看看commongenius的回答是一个很好的方法来做到这一点。

从.Net 3开始,有一个CompositeCollection类,它允许包含多个唯一项甚至集合。 WPF开发人员使用它来存储和显示Xaml中的不同项。 但这并不意味着它不能用于非WPF情况。

下面是一个示例,我将不同的东西从字符串存储到小数,并提取和枚举所有项目,然后是特定类型的项目:

 CompositeCollection cc = new CompositeCollection(); cc.Add(1); cc.Add("Item One"); cc.Add(1.0M); cc.Add(1.0); cc.Add("Done"); Console.WriteLine ("Every Item"); foreach (var element in cc) Console.WriteLine ("\t" + element.ToString()); Console.WriteLine (Environment.NewLine + "Just Strings"); foreach (var str in cc.OfType()) Console.WriteLine ("\t" + str); /* Outputs: Every Item 1 Item One 1.0 1 Done Just Strings Item One Done */ 

我相信你的集合都必须是相同的MyClass类型(因为T必须是相同的),因为编译器不会知道你添加到集合中哪些元素的类型。

换句话说,如果要向列表中添加2个元素:

 list.Add(new MyClass()); list.Add(new MyClass()); 

然后尝试引用一个:

 var myItem = list[1]; 

编译器不知道在元素1处为通配分配给MyClass列表的是什么,因为元素是在运行时添加的,但是generics是在编译时确定的。

我很确定你想要做的事情无法完成。


如果你事先知道元素的数量,也许你可以使用元组 ?

IList的

无法定义可以接受任何通用类风格的generics集合…即IList 。 通用类只是开发人员在编写一堆重复代码时节省的捷径,但在编译时,generics类的每种风格都被转换为具体的。 即如果您有MyClassMyClassMyClass那么编译器将生成3个单独且不同的类。 做你想做的事的唯一方法是为你的generics提供一个接口。

 public interface IMyGeneric { Type MyType { get; set;} } class MyGeneric : IMyGeneric { public MyGeneric() { MyType = typeof(T); } public Type MyType { get; set; } } 

然后你可以说

 IList list = new List(); list.add(new MyGeneric()); list.add(new MyGeneric());