我有一个这样的泛型类:
public class Foo<T>
{
public string SomeMethod();
...
}
我希望存储对这种类型的不同通用实例的引用列表。例如
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 上的编译器错误。添加呼叫说:
"Cannot convert from 'Foo<string>' to 'Foo<object>'
如何存储类型不同的泛型类型实例列表?
我不想只存储对象列表(ArrayList、List、List 等),并且必须使用反射来访问它们的成员!
DoSomething()
不需要Foo<T>
中的T
。因此,您可以通过创建用于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());
}
你想创建一个新的接口,把你的 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();
}
}
在某些情况下,这种协方差可能非常有用。