型がC#リフレクションを備えたインターフェイスを実装しているかどうかを判断する方法


562

リフレクションC#、特定のSystem.Type型がインターフェイスをモデル化しているかどうかを判断する方法を提供しますか?

public interface IMyInterface {}

public class MyType : IMyInterface {}

// should yield 'true'
typeof(MyType)./* ????? */MODELS_INTERFACE(IMyInterface);

回答:


969

いくつかの選択肢があります。

  1. typeof(IMyInterface).IsAssignableFrom(typeof(MyType))

  2. typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface))

汎用インターフェースの場合、少し異なります。

typeof(MyType).GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMyInterface<>))

68
typeof(IMyInterface).IsAssignableFrom(typeof(IMyInterface))もtrueであることを忘れないでください。これは、コードに予期しない結果をもたらす可能性があります。
クリス・ケンプ

29
注意を払わず、IsAssignableFrom逆向きの議論をするのは簡単でした。私はGetInterfaces今から行きます:p
ベンジャミン

12
IsAssignableFrom(t1)バリアントは速くよりも3倍程度であるGetInterfaces().Contains(t2)私のコードで対応。
ピエールアルノー2013年

24
@PierreArnaud:IsAssignableFromは最終的にGetInterfacesを呼び出すため、おそらくテストでは最初にGetInterfacesをチェックし、その後でIsAssignableをチェックします。これは、GetInterfacesが結果をキャッシュするため、最初の呼び出しのコストが高くなります
Panos Theof

17
@Kostaの回答に対する小さな変更。C#6を使用するとtypeof(MyType).GetInterface(nameof(IMyInterface)) != null、型の安全性とリファクタリングを向上させることができます。
aholmes 2016年


32
typeof(IMyInterface).IsAssignableFrom(someclass.GetType());

または

typeof(IMyInterface).IsAssignableFrom(typeof(MyType));

34
クラスのインスタンスが既にある場合は、someclass is IMyInterfaceリフレクションのコストがまったく含まれないため、はるかに優れたアプローチになります。したがって、間違いではありませんが、それを行うための理想的な方法ではありません。
James J. Regan IV、

1
@ジェームズ-そうですね。Resharperも同じ提案をします。
Angshuman Agarwal 2013

@ JamesJ.ReganIVあなたは答えとしてそれを投稿するべきです、私はほとんどあなたのコメントを見逃しました
reggaeguitar 14

@reggaeguitar、ありがとう、しかしコメントは元の質問に答えません。質問はReflectionソリューションを要求します。この回答の最初のケースでは、オブジェクトReflectionのインスタンスがあるのは理想的なソリューションではありません。
James J. Regan IV

1
@ JamesJ.ReganIV実際にisは、継承階層の両方向をチェックしますが、上方向IsAssignableFromのみをチェックします。また、オブジェクトのインスタンスがある場合は、呼び出す必要がありますIsInstanceOfType(これも上向きにしか見えません)。
Sellorio 2017年

13
public static bool ImplementsInterface(this Type type, Type ifaceType) 
{
    Type[] intf = type.GetInterfaces();
    for(int i = 0; i < intf.Length; i++) 
    {
        if(intf[ i ] == ifaceType) 
        {
            return true;
        }
    }
    return false;
}

次の3つの理由から、これは正しいリリースだと思います。

  1. IsAssignableFromではなくGetInterfacesを使用します。IsAssignableFromは最終的にいくつかのチェックがGetInterfacesを呼び出した後なので、より高速です。
  2. ローカル配列を反復処理するため、境界チェックは行われません。
  3. Typeに定義されている==演算子を使用しているため、Equalsメソッドよりも安全です(Contains呼び出しが最終的に使用します)。

10
コンテンツの+1ですが、私は括弧とエジプトのブレースの周りのスペースが嫌いです。また、メソッド全体を次のように記述することもできます。return type.GetInterfaces()。Any(t => t == ifaceType);
reggaeguitar 2014年

1
Type.IsAssignableFrom()は、内部的にはコードとまったく同じように機能します
devi

1
また、なぜLINQを使用しないtype.GetInterfaces()。Contains(ifaceType)ではないのか。

9

今やりました:

public static bool Implements<I>(this Type source) where I : class
{
  return typeof(I).IsAssignableFrom(source);
}

私が言っていることがしたいwhere I : interface、しかしinterface、一般的なパラメータ制約オプションではありません。classできるだけ近づいています。

使用法:

if(MyType.Implements<IInitializable>())
  MyCollection.Initialize();

私が言ったのはImplements、それがより直感的だからです。私はいつもIsAssignableFromフリップフロップします。


return typeof(I).IsInterface && typeof(I).IsAssignableFrom(source);メソッドの「誤った」使用方法でfalseを返すこともできます。インターフェイスタイプではなくクラスタイプで使用すると、type-parameterがインターフェイスでない場合は例外がスローされます。派生クラスは「実装」していると主張できますが、それは親です...
SindriJóelsson

7

最適なパフォーマンスを得るためにJeffの回答を変更します(Pierre Arnaudによるパフォーマンステストのおかげです)。

var type = typeof(MyType);
var implementsInterface = typeof(IMyInterface).IsAssignableFrom(type) && type.IsClass;

特定のインターフェイスを実装するすべてのタイプを見つけるにはAssembly

var implementations = typeof(TypeInTargetAssembly).Assembly.GetTypes()
                          .Where(t => typeof(IMyInterface).IsAssignableFrom(t) && t.IsClass);

7

他の誰かがすでに述べたように:ベンジャミン、2013年4月10日22時21分に」

注意を払わず、IsAssignableFromの引数を逆方向に取得するのは簡単でした。今はGetInterfacesを使います:p –

さて、もう1つの方法は、「最も一般的な」考え方をある程度満たす短い拡張メソッドを作成することです(これは、個人の好みに基づいて少し「より自然」にするための非常に小さな個人的な選択であることに同意しました) ):

public static class TypeExtensions
{
    public static bool IsAssignableTo(this Type type, Type assignableType)
    {
        return assignableType.IsAssignableFrom(type);
    }
}

そして、なぜもう少し一般的なことをしないのですか(本当にそれが本当に興味深いかどうかはわかりませんが、「シンタックス」の砂糖の別のピンチを渡していると思います):

public static class TypeExtensions
{
    public static bool IsAssignableTo(this Type type, Type assignableType)
    {
        return assignableType.IsAssignableFrom(type);
    }

    public static bool IsAssignableTo<TAssignable>(this Type type)
    {
        return IsAssignableTo(type, typeof(TAssignable));
    }
}

その方がずっと自然だと思いますが、ここでも非常に個人的な意見の問題です。

var isTrue = michelleType.IsAssignableTo<IMaBelle>();

4
拡張メソッドに実装を直接配置しなかった理由はありますか?つまり、これで両方の方法でそれを呼び出すことができますが、なぜそれを行う必要があるのですか?
Mark A. Donohoe 2017年

@MarqueIVが2年近く遅れてご返答して申し訳ありません。まあ、コードの繰り返しを避けるために拡張メソッドにヘルパーメソッドをラップするのは古い悪い習慣だったと思います。私の答えを編集します:)
Kerry Perret

1
@MarqueIV done plusは、エイリアスを使用しない他の悪い習慣、つまりBoolean=>を変更しましたbool(私が若い頃にコーディングの厳密な「ファンシー」なルールを使用していたのはなぜですか)。
ケリーペレット

3

タイプまたはインスタンスがある場合、それらが特定のインターフェースをサポートしているかどうかを簡単に確認できます。

オブジェクトが特定のインターフェースを実装しているかどうかをテストするには:

if(myObject is IMyInterface) {
  // object myObject implements IMyInterface
}

型が特定のインターフェースを実装しているかどうかをテストするには:

if(typeof(IMyInterface).IsAssignableFrom(typeof(MyType))) {
  // type MyType implements IMyInterface
}

汎用オブジェクトがあり、キャストと、キャスト先のインターフェースが実装されているかどうかのチェックを行う場合、コードは次のとおりです。

 var myCastedObject = myObject as IMyInterface;

    if(myCastedObject != null) {
      // object myObject implements IMyInterface
    }

2

IsAssignableFromに移動しましたTypeInfo

typeof(ISMSRequest).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo());

1

これを検索する人は誰でも、次の拡張メソッドが便利だと思うかもしれません:

public static class TypeExtensions
{
    public static bool ImplementsInterface(this Type type, Type @interface)
    {
        if (type == null)
        {
            throw new ArgumentNullException(nameof(type));
        }

        if (@interface == null)
        {
            throw new ArgumentNullException(nameof(@interface));
        }

        var interfaces = type.GetInterfaces();
        if (@interface.IsGenericTypeDefinition)
        {
            foreach (var item in interfaces)
            {
                if (item.IsConstructedGenericType && item.GetGenericTypeDefinition() == @interface)
                {
                    return true;
                }
            }
        }
        else
        {
            foreach (var item in interfaces)
            {
                if (item == @interface)
                {
                    return true;
                }
            }
        }

        return false;
    }
}

xunitテスト:

public class TypeExtensionTests
{
    [Theory]
    [InlineData(typeof(string), typeof(IList<int>), false)]
    [InlineData(typeof(List<>), typeof(IList<int>), false)]
    [InlineData(typeof(List<>), typeof(IList<>), true)]
    [InlineData(typeof(List<int>), typeof(IList<>), true)]
    [InlineData(typeof(List<int>), typeof(IList<int>), true)]
    [InlineData(typeof(List<int>), typeof(IList<string>), false)]
    public void ValidateTypeImplementsInterface(Type type, Type @interface, bool expect)
    {
        var output = type.ImplementsInterface(@interface);
        Assert.Equal(expect, output);
    }
}

0

どうですか

if(MyType as IMyInterface != null)


4
これは、インスタンスがある場合は明らかです。リフレクションからのタイプがある場合は有用ではありません
edc65

0

どうですか

typeof(IWhatever).GetTypeInfo().IsInterface

0

正解は

typeof(MyType).GetInterface(nameof(IMyInterface)) != null;

しかしながら、

typeof(MyType).IsAssignableFrom(typeof(IMyInterface));

次のコードが文字列とIConvertibleで示すように、誤った結果を返す可能性があります。

    static void TestIConvertible()
    {
        string test = "test";
        Type stringType = typeof(string); // or test.GetType();

        bool isConvertibleDirect = test is IConvertible;
        bool isConvertibleTypeAssignable = stringType.IsAssignableFrom(typeof(IConvertible));
        bool isConvertibleHasInterface = stringType.GetInterface(nameof(IConvertible)) != null;

        Console.WriteLine($"isConvertibleDirect: {isConvertibleDirect}");
        Console.WriteLine($"isConvertibleTypeAssignable: {isConvertibleTypeAssignable}");
        Console.WriteLine($"isConvertibleHasInterface: {isConvertibleHasInterface}");
    }

結果:

 isConvertibleDirect: True
 isConvertibleTypeAssignable: False
 isConvertibleHasInterface: True

4
受け入れられた回答でわかるように、使用方法のタイプを交換しましたIsAssignableFrom。ベンジャミンとエウアーンが警告するように。
VV5198722

0

ジェネリックインターフェイスがある場合IMyInterface<T>、これは常に返されfalseます。

  typeof(IMyInterface<>).IsAssignableFrom(typeof(MyType)) /* ALWAYS FALSE */

これも機能しません:

  typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface<>))  /* ALWAYS FALSE */

ただし、これをMyType実装すると、IMyInterface<MyType>これは機能し、次を返しますtrue

  typeof(IMyInterface<MyType>).IsAssignableFrom(typeof(MyType))

ただし、T実行時にはタイプパラメータがわからない可能性があります。ややハックな解決策は:

  typeof(MyType).GetInterfaces()
                .Any(x=>x.Name == typeof(IMyInterface<>).Name)

ジェフのソリューションは少しハックが少ないです:

  typeof(MyType).GetInterfaces()
         .Any(i => i.IsGenericType 
             && i.GetGenericTypeDefinition() == typeof(IMyInterface<>));

以下はType、どのような場合でも機能する拡張メソッドです。

public static class TypeExtensions
{
    public static bool IsImplementing(this Type type, Type someInterface)
    {
        return type.GetInterfaces()
             .Any(i => i == someInterface 
                 || i.IsGenericType 
                    && i.GetGenericTypeDefinition() == someInterface);
    }
}

(上記では、おそらくループよりも遅いlinqを使用していることに注意してください。)

その後、次のことができます。

   typeof(MyType).IsImplementing(IMyInterface<>)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.