7

実行時に型が宣言されるジェネリック List<> を作成したいと考えています。

次のことができますが、動的であるため、速度にペナルティがあると思われます。私はエキゾチックなデータベースのラッパーを書いているので、速度が重要です。

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

この投稿を動的ジェネリック型で読みましたが、機能しません。具体的には、オブジェクトはリストとして表示されないため、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

List<dynamic>は、たとえば、値の型のボクシングを超えてList<object>、型指定された に対して速度のペナルティなしで、まったく同じ型をコンパイルします。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 に答える
1

In your case, gdb will always be a System.Object, as CreateInstance returns objects of any type.

You have a few options here - you could cast it as IList (non-generic), as you know that List<T> implements this interface, and use IList.Add.

Alternatively, you could just declare it dynamic, and use dynamic binding:

dynamic gdb = Activator.CreateInstance(specificListType);

This will let you write your code as if it's a List<T> of the appropriate type, and the calls will be bound at runtime via dynamic binding.

于 2012-10-24T16:03:17.620 に答える