如果我有一个通用类:
public class MyClass<T>
{
public T Value;
}
我想实例化几个项目,例如......
new MyClass<string>
new MyClass<int>
...并将它们添加到集合中。如何定义集合以便它可以包含泛型类型列表?然后我想在某个时刻迭代集合,并使用Value属性。可能?
答案 0 :(得分:29)
让您的泛型类继承非泛型基类,或实现非泛型接口。然后,您可以拥有此类型的集合,并在您用于访问集合内容的任何代码中进行强制转换。
这是一个例子。
public abstract class MyClass
{
public abstract Type Type { get; }
}
public class MyClass<T> : 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<T> objects.
public class MyClassCollection
{
private Dictionary<Type, MyClass> _dictionary;
public MyClassCollection()
{
_dictionary = new Dictionary<Type, MyClass>();
}
public void Put<T>(MyClass<T> item)
{
_dictionary[typeof(T)] = item;
}
public MyClass<T> Get<T>()
{
return _dictionary[typeof(T)] as MyClass<T>;
}
}
答案 1 :(得分:8)
我能想到的唯一方法,如下所示(包含在控制台应用程序中进行测试):
class Program
{
static void Main(string[] args)
{
var x = new MyClass<string>() { Value = "34" };
var y = new MyClass<int>() { Value = 3 };
var list = new List<IMyClass>();
list.Add(x);
list.Add(y);
foreach (var item in list)
{
Console.WriteLine(item.GetValue);
}
}
private interface IMyClass
{
object GetValue { get; }
}
private class MyClass<T> : IMyClass
{
public T Value;
public object GetValue
{
get
{
return Value;
}
}
}
}
即。让MyClass实现一个空接口,然后创建一个包含实现该接口的类实例的集合。
<强>更新强> 我在接口中添加了一个“GetValue”方法,允许您以对象的形式访问MyClass实例的“Value”。如果你想拥有一个包含混合类型的集合,这就像它将要获得的那样好。
答案 2 :(得分:3)
您需要为MyClass定义基类,然后您的集合将是基类列表。例如:
void Main()
{
var a = new MyClass<string>();
var b = new MyClass<int>();
var c = new List<MyBase>();
c.Add(a);
c.Add(b);
}
public class MyBase { }
// Define other methods and classes here
public class MyClass<T> : MyBase {
public T Value { get; set;}
}
答案 3 :(得分:3)
您希望拥有一个MyClass集合,其中每个实例中类型参数T的值都不同。这在.NET中是不可能的;它缺少Java通配符(?)的等价物。您需要做的是创建一个非通用的基类或接口,MyClass可以实现它。例如:
public interface IMyClass {
object Value { get; set; }
}
public class MyClass<T> : IMyClass {
public T Value { get; set; }
object IMyClass.Value {
get { return Value; }
set { Value = (T)value; }
}
}
List<IMyClass> m = new List<IMyClass> { new MyClass<string>(), new MyClass<int> };
答案 4 :(得分:3)
我的大多数泛型类型都有“Untyped”成员接口:
private interface IMyClass
{
object UntypedValue { get; }
}
private class MyClass<T> : IMyClass
{
T Value { get; set; }
object UntypedValue { get { return Value; } }
}
您也可以通过使用显式接口实现来完成此操作,但在我看来,使用单独的名称会更容易。 (关于显式接口实现也有一些CA提示)
答案 5 :(得分:2)
我认为这里的问题是泛型类实际上根本不是同一类型。它们只是在编译时创建全新类型的模板(如果我理解正确的话)。因此,根据运行时,MyClass<int>
和MyClass<string>
完全不同的类型。他们可能也是MyIntClass
和MyStringClass
,你显然不能在同一个列表中没有先装箱。它们(必然)不继承相同的基类,实现相同的接口或其他任何东西。它们和其他两种类型一样不同,你必须这样对待它们(即使你认为你知道的更好)。
当然,您可以让它们实现接口,继承基础对象或已经给出的任何其他选项。请查看commongenius' answer以获得实现此目的的好方法。
答案 6 :(得分:2)
自.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<string>())
Console.WriteLine ("\t" + str);
/* Outputs:
Every Item
1
Item One
1.0
1
Done
Just Strings
Item One
Done
*/
答案 7 :(得分:1)
我相信你的集合都必须是相同的MyClass类型(因为T必须是相同的),因为编译器不会知道你添加到集合中哪些元素的类型。 / p>
换句话说,如果你要在列表中添加2个元素:
list.Add(new MyClass<string>());
list.Add(new MyClass<int>());
然后尝试引用一个:
var myItem = list[1];
编译器不知道在元素1处为MyClass列表分配了什么泛型,因为元素是在运行时添加的,但泛型是在编译时确定的。
我很确定你想要做的事情无法完成。
如果您事先知道元素的数量,也许您可以使用Tuple?
答案 8 :(得分:1)
的IList
无法定义可以接受任何通用类风格的通用集合......即IList<MyClass>
。通用类只是开发人员在编写一堆重复代码时节省的捷径,但在编译时,泛型类的每种风格都被转换为具体的。即如果您有MyClass<string>
,MyClass<int>
,MyClass<bool>
,则编译器将生成3个单独且不同的类。做你想做的事的唯一方法是为你的泛型提供一个接口。
public interface IMyGeneric {
Type MyType { get; set;}
}
class MyGeneric<T> : IMyGeneric {
public MyGeneric() {
MyType = typeof(T);
}
public Type MyType {
get; set;
}
}
然后你可以说
IList<IMyGeneric> list = new List<IMyGeneric>();
list.add(new MyGeneric<string>());
list.add(new MyGeneric<int>());
答案 9 :(得分:0)
另一种方法是使用非泛型类,并将处理程序传递给它以“从内部”执行操作。
interface IMyClass
{
void ShowValues(MyHandler handler);
}
// Contains a List<string>.
class MyClassString : IMyClass
{
private List<string> _list = new List<string> { "hello", "world" };
public void ShowValues(MyHandler handler)
{
handler.ShowValues(_list);
}
}
// Contains a List<int>.
class MyClassInt : IMyClass
{
private List<int> _list = new List<int> { 1, 2 };
public void ShowValues(MyHandler handler)
{
handler.ShowValues(_list);
}
}
// Handler that has overloaded methods for all the supported types.
class MyHandler
{
public void ShowValues(IEnumerable<string> list)
{
foreach (var item in list)
{
Console.WriteLine(item);
}
}
public void ShowValues(IEnumerable<int> list)
{
foreach (var item in list)
{
Console.WriteLine(item);
}
}
}
class Program
{
static void Main(string[] args)
{
var myClasses = new IMyClass[]
{
new MyClassString(),
new MyClassInt(),
};
var myHandler = new MyHandler();
foreach (var myClass in myClasses)
{
myClass.ShowValues(myHandler);
}
}
}