C#动态通用列表

时间:2012-10-24 15:59:42

标签: c# c#-4.0 generics dynamic type-conversion

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

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

List<dynamic> gdb = new List<dynamic>()

我在动态泛型类型中阅读this post,但无法使其工作。具体来说,该对象不会显示为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<System.Int32>
List<System.Int64>
List<System.String>

4 个答案:

答案 0 :(得分:5)

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

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

请注意,如果您添加的类型与通用类型不匹配,则上述内容会引发ArgumentException

答案 1 :(得分:3)

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

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

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

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

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

答案 2 :(得分:1)

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

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

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

dynamic gdb = Activator.CreateInstance(specificListType);

这将允许您编写代码,就好像它是适当类型的List<T>一样,并且调用将在运行时通过动态绑定进行绑定。

答案 3 :(得分:1)

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

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

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

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

IList gdb;

switch (trail[dataPos].Type)
{
    case GlobalsSubscriptTypes.Int32:
        gdb = new List<int>();
        break;
    case GlobalsSubscriptTypes.Int64:
        gdb = new List<long>();
        break;
    default:
        gdb = new List<string>();
        break;
}

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

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