2

代码示例:

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>

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

4

3 回答 3

4

您只是不能像在代码片段中尝试那样使用 C# 泛型。

为了使用 [C#] 泛型,必须在编译时知道实际的对象类型。

您正在尝试将对象类型作为类型参数动态传递。这根本不可能。

编辑

是的,可以使用反射动态创建通用对象。毕竟,泛型既是作为编译时 C# 构造实现的,也是作为 .NET 框架特性实现的(与 Java 相对,后者只是基于类型擦除的编译时特性)。因此,在 .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);
    }

    ...
}

因此,即使可能,使用反射来动态创建通用容器对于这个特定的用例来说似乎有点过分了。

于 2013-09-05T00:31:23.647 回答
4

你可以用反射来做到这一点

var entryType = typeof(Entry<>);
Type[] typeArgs = { o.GetType() };
var genericType = entryType.MakeGenericType(typeArgs);
IEntry entry = (IEntry)Activator.CreateInstance(genericType);
于 2013-09-05T00:23:03.840 回答
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));
}
于 2013-09-05T00:58:16.623 回答