【问题标题】:Declare a generic type instance dynamically [duplicate]动态声明泛型类型实例[重复]
【发布时间】:2008-11-21 05:47:38
【问题描述】:

是否可以在设计时不知道类型的情况下声明泛型的实例?

例子:

Int i = 1;
List<typeof(i)> list = new List<typeof(i)>();

i 的类型可以是任何东西,而不是必须做:

List<int> list = new List<int();

【问题讨论】:

    标签: c# .net generics


    【解决方案1】:

    如果您在编译时不知道类型,但您想要实际类型(即不是 List&lt;object&gt;并且您不在具有适当的泛型方法/类型类型参数,那么你必须使用反射。

    为了使反射更简单,我有时会在自己的代码中引入一个新的泛型类型或方法,因此我可以通过反射调用它,但之后只需使用普通泛型即可。例如:

    object x = GetObjectFromSomewhere();
    // I want to create a List<?> containing the existing
    // object, but strongly typed to the "right" type depending
    // on the type of the value of x
    MethodInfo method = GetType().GetMethod("BuildListHelper");
    method = method.MakeGenericMethod(new Type[] { x.GetType() });
    object list = method.Invoke(this, new object[] { x });
    
    // Later
    
    public IList<T> BuildListHelper<T>(T item)
    {
        List<T> list = new List<T>();
        list.Add(item);
        return list;
    }
    

    当然,如果你不知道类型,你以后不能对列表做很多事情......这就是为什么这种事情经常失败的原因。但并非总是如此 - 我曾多次使用上述类似的东西,但类型系统并不能让我静态地表达我需要的所有内容。

    编辑:请注意,尽管我在上面的代码中调用 Type.GetMethod,但如果您要执行很多次,您可能只想调用一次 - 毕竟,该方法不会改变。您可以将其设为静态(在上述情况下可以),并且您可能也希望将其设为私有。为了简化示例代码中的 GetMethod 调用,我将其保留为公共实例方法 - 否则您需要指定适当的绑定标志。

    【讨论】:

    • 你可以返回一个非泛型的 IList(List 支持),那么返回的列表就可以使用了。
    • 在这种情况下,使用 ArrayList 开始会更简单。
    • 啊,但是当它被强制转换为 IList 时将错误的类型添加到集合中仍然会出现关于它是错误类型的异常,不是吗?
    • 是的,它会抛出异常。
    • 12 年后,这个答案再次帮助了我!谢谢@JonSkeet
    【解决方案2】:

    我认为你能做的最好的事情是这样的:

    static void Main(string[] args)
    {
        int i = 1;
        var thelist = CreateList(i);
    }
    
    public static List<T> CreateList<T>(T t)
    {
        return new List<T>();
    }
    

    【讨论】:

    • 这依赖于编译器能够推断类型 - 这意味着它必须在编译时知道类型。
    【解决方案3】:

    如果您在设计时不知道类型,我会说您有一个 OBJECTS 列表(所有其他类型的基类)。

    List<object> list = new List<object>();
    

    【讨论】:

    • 不,您仍然可以创建适当类型的列表并将其传递给可能能够对正确类型进行强制转换的东西,然后以静态类型的方式使用它。仅仅因为一段代码不知道类型并不意味着 nothing 知道类型。
    【解决方案4】:

    您也可以使用 Activator.CreateInstance。示例代码sn-p:

    public class BaseRepository<T> where T : DataContext
    {
       protected T _dc;
    
       public BaseRepository(string connectionString)
       {
          _dc = (T) Activator.CreateInstance(typeof(T), connectionString);
       }
    
       public void SubmitChanges()
       {
          _dc.SubmitChanges();
       }
    }
    

    【讨论】:

      【解决方案5】:

      如果您仍想键入 .Add()、.Remove()、foreach 等,您可以将 List 视为常规的“旧”System.Collections.IList, 因为这个接口幸运地是由 List 实现的。

      而且由于该问题的所有其他已发布答案几乎都显示了动态创建 List 实例的所有其他可能方式, 我将展示最后一种方法。 我个人在创建泛型实例时使用此方法,当我在编译时对类型一无所知时, 并且类型必须作为字符串传递,可能来自应用程序配置文件。 在这个例子中,为了简单起见,T 是 System.String,但它可以是任何东西:

      Type T = typeof ( string ); // replace with actual T
      string typeName = string.Format (
        "System.Collections.Generic.List`1[[{0}]], mscorlib", T.AssemblyQualifiedName );
      
      IList list = Activator.CreateInstance ( Type.GetType ( typeName ) )
        as IList;
      
      System.Diagnostics.Debug.Assert ( list != null ); //
      
      list.Add ( "string 1" ); // new T
      list.Add ( "string 2" ); // new T
      foreach ( object item in list )
      {
        Console.WriteLine ( "item: {0}", item );
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多