我有一个像这样的泛型类:
public class Foo<T>
{
public string SomeMethod();
...
}
我希望存储对此类型的不同通用实例的引用列表。 e.g。
List<Foo<object>> foos = new List<Foo<object>>();
foos.Add(new Foo<string>());
foos.Add(new Foo<int>());
foos.Add(new Foo<Person>());
// Then do some processing like ...
foreach (var Foo<object> in foos)
{
Console.WriteLine(foo.SomeMethod());
}
etc...
foos.Add调用上的编译器错误说:
"Cannot convert from 'Foo<string>' to 'Foo<object>'
如何存储类型不同的泛型类型实例列表?
我不想只存储一个对象列表(ArrayList,List,List等),并且必须使用反射来访问它们的成员!
答案 0 :(得分:6)
T
不需要Foo<T>
DoSomething()
。因此,您可以通过为DoSomething()
创建接口并将对象存储在该接口的List<>
中来轻松解决问题:
public interface ISomethingDoer {
void DoSomething();
}
public class Foo<T> : ISomethingDoer {
public void DoSomething() { }
}
和 -
List<ISomethingDoer> foos = new List<ISomethingDoer>();
foos.Add(new Foo<string>());
foos.Add(new Foo<int>());
foos.Add(new Foo<Person>());
// Then do some processing like ...
foreach (var foo in foos)
{
Console.WriteLine(foo.DoSomething());
}
答案 1 :(得分:2)
您想要创建一个新界面,并将SomeMethod()放入其中,让您的通用实现它。这是最简单的解决方案。这就是他们存在的原因。
如果你的SomeMethod依赖于T,那么你需要研究界面协方差和逆变。
class Program
{
public interface IFoo
{
void DoSomething();
}
public interface IGenericFoo<out T> : IFoo
{
T GetDefault();
}
public class Foo<T> : IGenericFoo<T>
{
public T GetDefault()
{
return default(T);
}
public void DoSomething()
{
Console.WriteLine("Meep!");
}
}
private static void Main()
{
var fooCollection = new List<IFoo>
{
new Foo<string>(),
new Foo<StringBuilder>(),
new Foo<int>()
};
foreach (var instance in fooCollection)
instance.DoSomething();
// Covariance example
var fooCollectionGenericI = new List<IGenericFoo<object>>
{
new Foo<string>(),
new Foo<StringBuilder>(),
// new Foo<int>() not possible since covariance is not supported on structs :(
};
foreach (var instance in fooCollectionGenericI)
{
var wxp = instance.GetDefault();
Console.WriteLine(wxp == null ? "NULL" : wxp.ToString());
}
Console.ReadLine();
}
}
这种协方差在某些情况下非常有用。