【问题标题】:Is it impossible to use Generics dynamically? [duplicate]动态使用泛型是不可能的吗? [复制]
【发布时间】:2008-10-24 15:22:52
【问题描述】:

我需要在运行时创建使用泛型的类的实例,例如 class<T>,但之前不知道它们将拥有的类型 T,我想做这样的事情:

public Dictionary<Type, object> GenerateLists(List<Type> types)
{
    Dictionary<Type, object> lists = new Dictionary<Type, object>();

    foreach (Type type in types)
    {
        lists.Add(type, new List<type>()); /* this new List<type>() doesn't work */
    }

    return lists;
}

...但我做不到。我认为不可能在泛型括号内用 C# 编写类型变量。还有其他方法吗?

【问题讨论】:

  • 您能说明为什么要在运行时创建类型安全的通用对象吗?
  • 我已经做过好几次了,尤其是在移植协议缓冲区时。
  • 我正在为我的工作中的持久性框架做一个适配器,类需要这些信息来执行它们的工作。

标签: c# generics


【解决方案1】:

你不能那样做 - 泛型的重点主要是 compile-time 类型安全 - 但你可以通过反射来做到这一点:

public Dictionary<Type, object> GenerateLists(List<Type> types)
{
    Dictionary<Type, object> lists = new Dictionary<Type, object>();

    foreach (Type type in types)
    {
        Type genericList = typeof(List<>).MakeGenericType(type);
        lists.Add(type, Activator.CreateInstance(genericList));
    }

    return lists;
}

【讨论】:

  • 再次感谢乔恩。 CreateInstance 是否需要一个空的构造函数?我没有,其实我需要在里面输入一个参数。
  • 它确实需要一个构造函数。如果您不想使用构造函数,可以在 System.Runtime.Serialization 程序集中使用 FormatterServices.GetUninitializedObject()。
  • @Victor: Activator.CreateInstance 有带参数的重载,或者您可以使用 Type.GetConstructor 然后调用它。基本上有很多方法可以从一个类型转到一个类型的实例 - 选择一个:)
  • 请注意,这段代码并没有创建任何类型的实例——只是 List,它不关心该类型有哪些构造函数。
【解决方案2】:

根据您调用此方法的频率,使用 Activator.CreateInstance 可能会很慢。另一种选择是执行以下操作:

私人词典> delegates = new Dictionary>();

    public Dictionary<Type, object> GenerateLists(List<Type> types)
    {
        Dictionary<Type, object> lists = new Dictionary<Type, object>();

        foreach (Type type in types)
        {
            if (!delegates.ContainsKey(type))
                delegates.Add(type, CreateListDelegate(type));
            lists.Add(type, delegates[type]());
        }

        return lists;
    }

    private Func<object> CreateListDelegate(Type type)
    {
        MethodInfo createListMethod = GetType().GetMethod("CreateList");
        MethodInfo genericCreateListMethod = createListMethod.MakeGenericMethod(type);
        return Delegate.CreateDelegate(typeof(Func<object>), this, genericCreateListMethod) as Func<object>;
    }

    public object CreateList<T>()
    {
        return new List<T>();
    }

在第一次点击时,它会为创建列表的通用方法创建一个委托,然后将其放入字典中。在随后的每次点击中,您只需调用该类型的委托。

希望这会有所帮助!

【讨论】:

  • 谢谢 jonni,我只调用了这个方法一次,否则保留一个委托将是一个不错的选择。
猜你喜欢
  • 2013-07-24
  • 1970-01-01
  • 2011-04-20
  • 1970-01-01
  • 2018-12-09
  • 1970-01-01
  • 2015-12-08
  • 2011-04-04
  • 1970-01-01
相关资源
最近更新 更多