C#,实例化泛型类型 - 带有变量类型参数?

时间:2013-09-05 00:05:34

标签: c# generics

代码示例:

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>

为什么不可能?我想我需要使用反射代替?如何正确和高效地做到这一点?

3 个答案:

答案 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显然不需要那样。

毕竟,entriesList<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));
}