代码示例:
void Foo(params object[] objects)
{
var entries = new List<IEntry>();
foreach(var o in objects)
{
var entry = new Entry<o.GetType()>(); // this doesn't work
entries.Add(entry);
}
...
}
Foo("hello", 5); // should fill entries with Entry<string> and Entry<int>
为什么不可能?我想我需要使用反射代替?如何正确和高效地做到这一点?
答案 0 :(得分:3)
你可以用反射
来做var entryType = typeof(Entry<>);
Type[] typeArgs = { o.GetType() };
var genericType = entryType.MakeGenericType(typeArgs);
IEntry entry = (IEntry)Activator.CreateInstance(genericType);
答案 1 :(得分:3)
你不能像在你的代码片段中那样使用C#泛型。
为了使用[C#]泛型,必须在编译时知道实际对象类型 。
您尝试将对象类型动态传递为类型参数。这根本不可能。
修改强>
是的,可以使用反射动态创建通用对象。毕竟,泛型既可以作为编译时C#构造实现,也可以作为.NET框架功能实现(而不是Java,它只是基于Type Erasure的编译时功能)。因此,在.NET中,通过反射,可以实现后者“绕过”前者(再次,在Java中是不可能的)。
但OP显然不需要那样。
毕竟,entries
是List<IEntry>
。 IOW,entries
容器不“知道”其元素的具体类型(因为它绑定到接口)。因此,如果要添加的每个元素都已实现IEntry
,那么这就足够了:
void Foo(params IEntry[] objects)
{
var entries = new List<IEntry>();
foreach(var o in objects)
{
entries.Add(o);
}
...
}
OTOH,如果这些对象没有实现IEntry
,那么OP只需要一个纯粹的,普通的,旧式的无类型对象列表:
void Foo(params object[] objects)
{
var entries = new List<object>();
foreach(var o in objects)
{
entries.Add(o);
}
...
}
因此,使用反射来动态创建通用容器,即使可能,对于这个特定的用例似乎也是过度的。
答案 2 :(得分:1)
您需要以下形式的功能:
Func<Type, IEntry>
我建议将静态函数添加到Foo的父级,如下所示:
public static IEntry Make(Type type)
在该函数内部,随意添加任何对您有意义的代码:
if (type == typeof(string))
{
return new StringEntry(); //Obviously some special logic based on the type.
}
else
{
//Default logic
return (IEntry) Activator.CreateInstance(typeof(Entry<>).MakeGenericType(type));
}