web-dev-qa-db-ja.com

ジェネリック型引数を考慮せずに、型がジェネリックインターフェイスを実装しているかどうかを確認する

インターフェースがあります

public interface MyInterface<TKey, TValue>
{
}

実装は無関係です。ここで、特定の型がそのインターフェースの実装であるかどうかを確認したいと思います。このメソッドは失敗します

public class MyClass : MyInterface<int, string>
{
}

しかし、私はチェックを行う方法がわかりません。

public void CheckIfTypeImplementsInterface(Type type)
{
    var result1 = typeof(MyInterface<,>).IsAssignableFrom(type); --> false
    var result2 = typeof(MyInterface<int,string>).IsAssignableFrom(type); --> true
}

Result1をtrueにするにはどうすればよいですか?

32

私の知る限り、これを行う唯一の方法は、すべてのインターフェースを取得し、汎用定義が必要なインターフェースタイプと一致するかどうかを確認することです。

bool result1 = type.GetInterfaces()
    .Where(i => i.IsGenericType)
    .Select(i => i.GetGenericTypeDefinition())
    .Contains(typeof(MyInterface<,>));

編集:ジョンがコメントで指摘しているように、あなたも行うことができます:

bool result1 = type.GetInterfaces()
    .Where(i => i.IsGenericType)
    .Any(i => i.GetGenericTypeDefinition() == typeof(MyInterface<,>));
45
Lee

通常、このような動作は、ジェネリック型パラメーターに依存しない機能がインターフェイスに含まれている場合にのみ必要です。インターフェースを制御できる場合、最良の解決策は、タイプに依存する部分をタイプに依存しない部分から継承させることです。たとえば、既存のコレクションインターフェースが存在しない場合、次のように定義できます。

interface ICountable 
  { CollectionAttribute Attributes {get;} int Count {get;} }
interface ICollection<T> : IEnumerable<T> ICountable
  { ... and other stuff ... }

そのようなことをICollectionで行った場合、IEnumerable<Animal>を期待していたが、IList<Cat>を実装するだけのCatListタイプのオブジェクトを取得したコードは、そのオブジェクトのCountメンバーを使用しても問題ありません(List<Animal>はジェネリックではないICollectionを実装していることに注意してください。他のIList<Animal>実装はそうではないかもしれません)。

このように、ICollection<Cat>を期待しているときにコードが何らかの理由でIEnumerable<Animal>Countメソッドを見つけるというタスクに行き詰まっている場合は、Dictionary<Type, Func<IEnumerable<Animal>, int>のようなものを構築して、CatListが実装されていることを確認することをお勧めします。 ICollection<Cat>.Count引数をICollection<Cat>にキャストし、Countを呼び出して結果を返すメソッドへのデリゲートを構築できます。そのような辞書がある場合、別のCatListが与えられれば、辞書からデリゲートを呼び出すだけで済みます。

3
supercat