C#:複数の型制約を満たすインスタンスを見つけて作成する方法
-
19-09-2019 - |
質問
複数の型制約を持つジェネリック メソッドがあるとします。これは次のとおりです。
public static void DoSomethingAwesome<T>(T thing)
where T : IThing, IAwesome, IComparable<T>
{
...
}
今....リフレクションを使用して、そこに送信できるものを作成するにはどうすればよいでしょうか?
それが 1 つの制約だけであれば、次のようにできることがわかっています。
var types = assembly
.GetTypes()
.Where(typeof (IThing).IsAssignableFrom)
foreach(var t in types)
DoSomethingAwesome((IThing) Activator.CreateInstance(t));
ただし、実際には複数のインターフェイスにキャストすることはできません...一体どうすればこれを解決できるでしょうか?私は今ここでほとんど道に迷っていると言えるかもしれません :P
タイトルが長くて複雑になってしまいました。これを何と呼ぶべきか分からなかったので、できれば改善してください。
解決
適切な型を見つけることに関する Reed と Loren の回答に追加すると、キャストによって DoSomethingAwesome を呼び出すことはまだできないことに注意してください。これは、おわかりのように、コンパイラにはインスタンス化されたオブジェクトを複数のインターフェイスにキャストする方法が用意されていないためです。次の 2 つのオプションがあります。
ithing、iawesome、icomparableに由来する新しいインターフェイスiawesomecomparablethingを作成するu003CT>、あなたのタイプにそれを実装してもらい、それにキャストしてください。
DoSomethingAwesome を呼び出すには、 反射。これを行うには、次のことを行います のMethodInfoを取得する必要があります。 DoSomethingAwesome ジェネリック メソッド 次に、 MethodInfo.MakeGenericMethod を この 3 つすべてを実装する型 インターフェイス。
(2)の例:
Type type = sometype; // For example found using reeds method
MethodInfo mgeneric = typeof(Awesomeiser).GetMethod("DoSomethingAwesome");
MethodInfo mspecific = mgeneric.MakeGenericMethod(new [] { type });
mspecific.Invoke(null, new [] { type });
他のヒント
私は推測しているあなたが行うことはできませんいくつかの理由があります。
var types = assembly
.GetTypes()
.Where(typeof (IThing).IsAssignableFrom && typeof (IAwesome).IsAssignableFrom))
あなたはすべての制約から割り当て可能だタイプを必要としています。最初の二つは容易であるが、第三のは少し複雑です。
// Using
static bool IsIComparable(Type thing)
{
foreach (Type interfaceType in thing.GetInterfaces())
{
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof (IComparable<>))
{
Type[] arguments = interfaceType.GetGenericArguments();
if (arguments.Length == 1)
{
if (arguments[0] == thing)
return true;
}
}
}
return false;
}
// This returns an enumerable of compatible types:
var types = assembly.GetTypes().Where( t =>
typeof(IThing).IsAssignableFrom(t) &&
typeof(IAwesome).IsAssignableFrom(t) &&
IsIComparable(t) );