web-dev-qa-db-ja.com

C#のジェネリック、変数の型をパラメーターとして使用

一般的な方法があります

bool DoesEntityExist<T>(Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

次の方法でメソッドを使用するにはどうすればよいですか:

Type t = entity.GetType();
DoesEntityExist<t>(entityGuid, transaction);

次のようなコンパイルエラーが発生し続けます。

型または名前空間名 't'が見つかりませんでした(usingディレクティブまたはAssembly参照がありませんか?)

DoesEntityExist<MyType>(entityGuid, transaction);

完全に動作しますが、毎回個別の型名でメソッドを呼び出すifディレクティブを使用したくありません。

118
Germstorm

ジェネリックに関するポイントは、compile-time型の安全性を与えることです。つまり、コンパイル時に型を知る必要があります。

can実行時にのみ既知の型でジェネリックメソッドを呼び出しますが、リフレクションを使用する必要があります。

// For non-public methods, you'll need to specify binding flags too
MethodInfo method = GetType().GetMethod("DoesEntityExist")
                             .MakeGenericMethod(new Type[] { t });
method.Invoke(this, new object[] { entityGuid, transaction });

うん.

代わりにcallingメソッドをジェネリックにし、型パラメーターとして型パラメーターを渡し、スタックの1レベル上の決定をプッシュできますか?

あなたが何をしているかについてもっと情報を提供できれば、それは助けになるでしょう。上記のようにリフレクションを使用する必要がある場合もありますが、適切なポイントを選択してそれを行う場合は、一度だけ行う必要があることを確認し、そのポイントより下のすべてで通常の方法でtypeパラメーターを使用できるようにすることができます。

159
Jon Skeet

これを回避する1つの方法は、暗黙的なキャストを使用することです。

bool DoesEntityExist<T>(T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

次のように呼び出します:

DoesEntityExist(entity, entityGuid, transaction);

さらに一歩進んで、拡張メソッドに変換できます(静的クラスで宣言する必要があります)。

static bool DoesEntityExist<T>(this T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

そう呼び出す:

entity.DoesEntityExist(entityGuid, transaction);
33
Joe Lloyd

あなたの質問を正しく理解しているかどうかはわかりませんが、次のようにコードを書くことができます。

bool DoesEntityExist<T>(T instance, ....)

次の方法でメソッドを呼び出すことができます。

DoesEntityExist(myTypeInstance, ...)

この方法では、型を明示的に記述する必要はありません。フレームワークはインスタンスから型を自動的に追い越します。

7
kosto

説明どおりに使用することはできません。ジェネリック型についてのポイントは、「コーディング時」にはそれらを知らないかもしれませんが、コンパイラはコンパイル時にそれらを解決できる必要があるということです。どうして?なぜなら、コンパイラーは内部で「オープン」ジェネリック型を使用するたびに新しいタイプ(クローズドジェネリック型と呼ばれることもある)を作成するためです。

つまり、コンパイル後、

DoesEntityExist<int>

とは異なるタイプです

DoesEntityExist<string>

これは、コンパイラがコンパイル時の型安全性を確保する方法です。

説明するシナリオでは、実行時に検査できる引数として型を渡す必要があります。

他の答えで述べたように、他のオプションはリフレクションを使用してオープン型からクローズ型を作成することですが、これはおそらく私が言う極端なニッチのシナリオ以外で推奨されます。

4
Rob Levine