C#动态通用列表

我想创建一个通用的List ,其类型在运行时声明。

我可以做到以下几点,但由于它是动态的,我怀疑存在速度惩罚。 我正在为异国情调的数据库编写一个包装器,因此速度至关重要。

List gdb = new List() 

我在动态generics类型中阅读了这篇文章 ,但无法让它发挥作用。 具体来说,该对象不会显示为List,因此没有添加方法。

  Type ac; switch (trail[dataPos].Type) { case GlobalsSubscriptTypes.Int32: ac = typeof(System.Int32); break; case GlobalsSubscriptTypes.Int64: ac = typeof(System.Int64); break; default: ac = typeof(System.String); break; } var genericListType = typeof(List); var specificListType = genericListType.MakeGenericType(ac); var gdb = Activator.CreateInstance(specificListType); 

如何让gdb显示为以下之一:

 List List List 

一旦使用了Activator.CreateInstance ,就可以将结果转换为适当的类型。 您可以使用IList例如:

 var gdb = (IList)Activator.CreateInstance(specificListType); gdb.Add(1); 

请注意,如果您要添加的类型与generics类型不匹配,则上面会抛出ArgumentException

哦, gdb 正确的类型。 由于您在运行时确定类型,因此编译器不知道它。 因此,它是静态类型为object ,并不显示Add方法。 您有几个选项可以解决这个问题:

  1. 将其转换为正确的类型:

     switch (trail[dataPos].Type) { case GlobalsSubscriptTypes.Int32: ((List) gdb).Add(...); break; ... default: ((List) gdb).Add(...); break; } 
  2. 转换为常见的超类型:

     ((System.Collections.IList) gdb).Add(...); 
  3. 使用动态调用:

     dynamic gdb = Activator.CreateInstance(specificListType); gdb.Add(...); 

在您的情况下, gdb将始终是System.Object ,因为CreateInstance返回任何类型的对象。

这里有几个选项 – 您可以将其转换为IList (非generics),因为您知道List实现此接口,并使用IList.Add

或者,您可以将其声明为dynamic ,并使用动态绑定:

 dynamic gdb = Activator.CreateInstance(specificListType); 

这将使您编写代码,就好像它是相应类型的List ,并且调用将在运行时通过动态绑定进行绑定。

List编译与List完全相同的类型,对类型化List没有速度惩罚,例如,超过装箱值类型。 但是如果你要向IList施放你仍然会有拳击惩罚FYI。

你可能遇到麻烦的是调用Activator (一种reflection方法),因为直接调用构造函数可能会慢得多。

这有什么关系吗? 除非您实际运行配置文件,否则您将无法知道,因为它始终取决于您的实际使用情况。

我最好的客人,你真正想做的是:

 IList gdb; switch (trail[dataPos].Type) { case GlobalsSubscriptTypes.Int32: gdb = new List(); break; case GlobalsSubscriptTypes.Int64: gdb = new List(); break; default: gdb = new List(); break; } 

此外,如果你真的需要在没有拳击的情况下进行操作,可以使用通用帮助方法来完成所有工作:

 switch (trail[dataPos].Type) { case GlobalsSubscriptTypes.Int32: return Helper(trail[dataPos]); case GlobalsSubscriptTypes.Int64: return Helper(trail[dataPos]); default: return Helper(trail[dataPos]); }