7

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

我可以执行以下操作,但由于它是动态的,我怀疑会有速度损失。我正在为异国情调的数据库编写包装器,因此速度至关重要。

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

我在动态泛型类型中阅读了这篇文章,但无法让它工作。具体来说,该对象没有以 List 的形式出现,因此没有 add 方法。

    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

4 回答 4

5

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

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

请注意,ArgumentException如果您添加的类型与泛型类型不匹配,则上面会抛出一个。

于 2012-10-24T16:03:54.297 回答
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(...);
    
于 2012-10-24T16:05:16.837 回答
1

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

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

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

dynamic gdb = Activator.CreateInstance(specificListType);

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

于 2012-10-24T16:03:17.620 回答
1

List<dynamic>List<object>编译与typed 上没有速度惩罚的完全相同的类型List<int>,例如,除了装箱值类型。但是,如果您要投到 IList,您仍然会受到拳击处罚,仅供参考。

调用(反射方法)可能会遇到麻烦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]);
}
于 2012-10-24T16:23:55.200 回答