インターフェイスを実装するすべてのタイプを取得する


553

リフレクションを使用して、最小限のコードでC#3.0 / .NET 3.5のインターフェイスを実装するすべての型を取得し、反復を最小限に抑えるにはどうすればよいですか?

これは私が書き直したいものです:

foreach (Type t in this.GetType().Assembly.GetTypes())
    if (t is IMyInterface)
        ; //do stuff

1
サンプルコードは機能しますか?あなたのif条件で偽陰性があります。
Orionii皇帝

3
Typeクラス(t)のインスタンスがインターフェイスを実装しているかどうかをテストしているため、上記のコードのifステートメントは常にfalseになります。
Liazy 2013年

回答:


807

鉱山はc#3.0ではこれでしょう:)

var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(p => type.IsAssignableFrom(p));

基本的に、最小反復回数は常に次のようになります。

loop assemblies  
 loop types  
  see if implemented.

194
リストにはインターフェース自体も含まれる場合があることに注意してください。最後の行を.Where(p => type.IsAssignableFrom(p) && !p.IsInterface);に変更して、フィルターで除外します(またはp.IsClass)。
jtpereyda 2013

39
注:この回答は誤りです。これは、「割り当ての互換性」をチェックしますが、インターフェースが実装されているかどうかはチェックしません。たとえば、List<string>実装されてIEnumerable<object>いませんが、このメソッドは.Net 4.0ではtrueを返しますが、これは共分散が実際に間違っているためです。正解はこちら
スリラムサクティベル、2014

20
@SriramSakthivelの最初の段階では、一般的な値は指定されていません。第二に、この質問は共分散以前のものです。第三に、共変リターンは彼らが望んでいるものではないと仮定します。
Darren Kopp、2014

24
あなたは間違いなく正しいです、これは古いスレッドであることを知っています。将来のユーザーがそのような問題が存在することを知らせるためにコメントを登録しました。あなたを怒らせないでください。質問のタイトルにあるように、OPがインターフェイスを実装するすべての型取得することを求めている場合このコードはそれを行っていません。しかし、ほとんどすべてのケースで機能します。私が言ったようにコーナーケースもあります。ただ気づくだけです。
Sriram Sakthivel、2014

9
クラスが抽象的でないことも確認する必要があります=>.Where(p => type.IsAssignableFrom(p) && p.IsClass && !p.IsAbstract
Jonesopolis

66

これでうまくいきました。クラスをループし、myInterfaceから派生したものかどうかを確認します。

 foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                 .Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) {
    //do stuff
 }

5
アセンブリがメインの実行可能ファイルにあると想定しています。追加のプロジェクトではありません。また、何度も繰り返して、不必要に反復している。フレームワークに重い作業を行わせることをお勧めします。次に、見つかったらさらにフィルタリングします。必要に応じて、回答を更新してください。リスト<T>の推論を含めます。var classTypesImplementingInterface = AppDomain.CurrentDomain.GetAssemblies()。SelectMany(x => x.GetTypes())。Where(mytype => typeof(myInterface).IsAssignableFrom(mytype)&& mytype.GetInterfaces()。Contains(typeof(myInterface) )); foreach(var item in items)Console.Log(item.Name);
TamusJRoyce 2014

58

IFooインターフェイスを実装するアセンブリ内のすべてのタイプを見つけるには:

var results = from type in someAssembly.GetTypes()
              where typeof(IFoo).IsAssignableFrom(type)
              select type;

ライアンリナルディの提案が正しくなかったことに注意してください。0のタイプを返します。書けない

where type is IFoo

タイプはSystem.Typeインスタンスであり、タイプIFooになることはないためです。代わりに、IFooがタイプから割り当て可能かどうかを確認します。期待どおりの結果が得られます。

また、現在回答としてマークされているアダム・ライトの提案も同様の理由で正しくありません。すべてのSystem.TypeインスタンスがIFooインプリメンターではなかったため、実行時に0タイプが返されることがわかります。


58

これは非常に古い質問であることに感謝しますが、これまでのすべての回答は何らかの形式を使用しているため、将来のユーザーのために別の回答を追加するつもりでしたAssembly.GetTypes

GetTypes()は実際にすべてのタイプを返しますが、必ずしもそれらをアクティブ化できることを意味するわけではないため、をスローする可能性がありReflectionTypeLoadExceptionます。

型が戻ったときであろうタイプを活性化することができないための古典的な例であるderivedから、baseしかしbaseとは異なるアセンブリで定義されderived、呼び出しがアセンブリしないアセンブリこと参照。

だから我々が持っていると言う:

Class A // in AssemblyA
Class B : Class A, IMyInterface // in AssemblyB
Class C // in AssemblyC which references AssemblyB but not AssemblyA

どちらがその中にClassCある場合、AssemblyC受け入れられた回答に従って何かを行います。

var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(p => type.IsAssignableFrom(p));

その後、それがスローされますReflectionTypeLoadException

これは、への参照がないとAssemblyAAssemblyC次のことができないためです。

var bType = typeof(ClassB);
var bClass = (ClassB)Activator.CreateInstance(bType);

言い換えれば、GetTypesへの呼び出しがチェックしてスローするものであるロード可能ではClassBありません。

したがって、ロード可能な型の結果セットを安全に修飾するには、このPhil Haackedの記事「アセンブリ内のすべての型Jon Skeetコードに従って代わりに次のようにします。

public static class TypeLoaderExtensions {
    public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) {
        if (assembly == null) throw new ArgumentNullException("assembly");
        try {
            return assembly.GetTypes();
        } catch (ReflectionTypeLoadException e) {
            return e.Types.Where(t => t != null);
        }
    }
}

その後:

private IEnumerable<Type> GetTypesWithInterface(Assembly asm) {
    var it = typeof (IMyInterface);
    return asm.GetLoadableTypes().Where(it.IsAssignableFrom).ToList();
}

3
これは、テストプロジェクトでGetTypesが失敗し、CI環境でのみ発生するという非常に奇妙な問題に対処するのに役立ちました。GetLoadableTypesは、このソリューションの修正でした。エラーはローカル環境では再現できず、これは次のとおりでした:System.Reflection.ReflectionTypeLoadException:要求されたタイプの1つ以上をロードできません。詳細については、LoaderExceptionsプロパティを取得してください。より具体的には、具体的な実装がないタイプがあり、単体テストプロジェクトで発生したという不満でした。これをありがとう!
Lari Tuomisto、2015年

2
この回答は解決策としてマークする必要があります。@ Lari Tuomistoが言ったように、ローカル環境では同様のエラーを再現できなかったため、今日は私のお尻を救いました
Lightning3

3
他の人を助ける場合:この解決策は私にとってはうまくいきましたが、インターフェイスの種類をリストから削除するために修正する必要がありました。CreateInstanceそれらすべてに対してアクティブ化したかったのですが、実際のインターフェースを作成しようとしたときに例外がスローされました(このソリューションでは実際のインターフェースが邪魔だと思っていたため、しばらく混乱していました)。そこで、コードをに変更しましたGetLoadableTypes(assembly).Where(interfaceType.IsAssignableFrom).Where(t => !(t.Equals(interfaceType))).ToList();
XavierPeña16年

21

ここで使用する他の回答IsAssignableFromここで説明するようにFindInterfacesSystem名前空間からも使用できます

現在実行中のアセンブリのフォルダー内のすべてのアセンブリをチェックし、特定のインターフェイスを実装するクラスを探す例を次に示します(明確にするためにLINQは避けます)。

static void Main() {
    const string qualifiedInterfaceName = "Interfaces.IMyInterface";
    var interfaceFilter = new TypeFilter(InterfaceFilter);
    var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    var di = new DirectoryInfo(path);
    foreach (var file in di.GetFiles("*.dll")) {
        try {
            var nextAssembly = Assembly.ReflectionOnlyLoadFrom(file.FullName);
            foreach (var type in nextAssembly.GetTypes()) {
                var myInterfaces = type.FindInterfaces(interfaceFilter, qualifiedInterfaceName);
                if (myInterfaces.Length > 0) {
                    // This class implements the interface
                }
            }
        } catch (BadImageFormatException) {
            // Not a .net assembly  - ignore
        }
    }
}

public static bool InterfaceFilter(Type typeObj, Object criteriaObj) {
    return typeObj.ToString() == criteriaObj.ToString();
}

複数を照合する場合は、インターフェースのリストを設定できます。


これは私が探していた文字列インターフェース名を探します。
センティル2013年

型を文字列にシリアル化する必要があるため、別のドメインにアセンブリを読み込むときに機能します。すごい!
TamusJRoyce

取得:アセンブリ 'System.Core、Version = 4.0.0.0、Culture = neutral、PublicKeyToken = b77a5c561934e089'への依存関係を解決できません。プリロードされていないためです。ReflectionOnly APIを使用する場合、依存アセンブリは、ReflectionOnlyAssemblyResolveイベントを通じてオンデマンドでプリロードまたはロードする必要があります。
bkwdesign

18

ロードされたすべてのアセンブリをループし、すべての型をループし、それらがインターフェイスを実装しているかどうかを確認します。

何かのようなもの:

Type ti = typeof(IYourInterface);
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) {
    foreach (Type t in asm.GetTypes()) {
        if (ti.IsAssignableFrom(t)) {
            // here's your type in t
        }
    }
}

8

これは私のために働きました(もしあなたがあなたがルックアップでシステムタイプを除外することができるなら):

Type lookupType = typeof (IMenuItem);
IEnumerable<Type> lookupTypes = GetType().Assembly.GetTypes().Where(
        t => lookupType.IsAssignableFrom(t) && !t.IsInterface); 

5

編集:元の質問は反復/コードの削減に関するものであり、それは演習として十分であり、そして実際の状況では、最速の実装を望んでいることを明確にするために編集を見たところです基になるLINQがどの程度クールかを示します。

次に、読み込まれた型を反復処理するためのUtilsメソッドを示します。独自の/サードパーティのコードベースでの実装を探している場合、excludeSystemTypesオプションは、通常のクラスとインターフェイスを処理し、excludeSystemTypesオプションは処理を大幅に高速化します。

public static List<Type> GetSubclassesOf(this Type type, bool excludeSystemTypes) {
    List<Type> list = new List<Type>();
    IEnumerator enumerator = Thread.GetDomain().GetAssemblies().GetEnumerator();
    while (enumerator.MoveNext()) {
        try {
            Type[] types = ((Assembly) enumerator.Current).GetTypes();
            if (!excludeSystemTypes || (excludeSystemTypes && !((Assembly) enumerator.Current).FullName.StartsWith("System."))) {
                IEnumerator enumerator2 = types.GetEnumerator();
                while (enumerator2.MoveNext()) {
                    Type current = (Type) enumerator2.Current;
                    if (type.IsInterface) {
                        if (current.GetInterface(type.FullName) != null) {
                            list.Add(current);
                        }
                    } else if (current.IsSubclassOf(type)) {
                        list.Add(current);
                    }
                }
            }
        } catch {
        }
    }
    return list;
}

それはきれいではない、私は認めます。


2
列挙子は、IDisposableを実装していますが、これはtry / finallyで破棄されていません。foreachまたはlinqを使用することをお勧めします。
TamusJRoyce

なぜexcludeSystemTypes1回で2回テストするのifですか?
NetMage

4

他の答えは、一般的なインターフェースでは機能しませんでした。

これは、typeof(ISomeInterface)をtypeof(T)に置き換えるだけです。

List<string> types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
            .Where(x => typeof(ISomeInterface).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
            .Select(x => x.Name).ToList();

だから

AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())

すべてのアセンブリを取得します

!x.IsInterface && !x.IsAbstract

インターフェースと抽象インターフェースを除外するために使用され、

.Select(x => x.Name).ToList();

リストにそれらを持っています。


ソリューションの仕組みと、他のすべての回答よりも優れている理由を説明してください。
LukasKörfer'19年

それは優れたものでも低くもない、他の答えは私にとってはうまくいかなかったので、私はわざわざそれを共有しました。
アントニンガブレル2018

私のコメントはあなたの答えがコードのみであるということだけだったので、いくつかの説明を追加するように頼みました。
LukasKörfer18年

2

(パフォーマンスの観点から)やりたいことを簡単に行う方法はありません。

リフレクションは、主にアセンブリと型で機能するため、アセンブリのすべての型を取得して、適切なインターフェイスについてクエリする必要があります。次に例を示します。

Assembly asm = Assembly.Load("MyAssembly");
Type[] types = asm.GetTypes();
Type[] result = types.where(x => x.GetInterface("IMyInterface") != null);

これにより、アセンブリMyAssemblyにIMyInterfaceを実装するすべてのタイプが取得されます


2

アセンブリの場所を選択するときはさらに良いです。実装されたすべてのインターフェースが同じAssembly.DefinedTypes内にあることがわかっている場合は、ほとんどのアセンブリをフィルターに掛けます。

// We get the assembly through the base class
var baseAssembly = typeof(baseClass).GetTypeInfo().Assembly;

// we filter the defined classes according to the interfaces they implement
var typeList = baseAssembly.DefinedTypes.Where(type => type.ImplementedInterfaces.Any(inter => inter == typeof(IMyInterface))).ToList();

Can Bilgin著



1

すでに多くの有効な回答がありますが、別の実装をType拡張として追加し、さまざまなシナリオを示す単体テストのリストを追加したいと思います。

public static class TypeExtensions
{
    public static IEnumerable<Type> GetAllTypes(this Type type)
    {
        var typeInfo = type.GetTypeInfo();
        var allTypes = GetAllImplementedTypes(type).Concat(typeInfo.ImplementedInterfaces);
        return allTypes;
    }

    private static IEnumerable<Type> GetAllImplementedTypes(Type type)
    {
        yield return type;
        var typeInfo = type.GetTypeInfo();
        var baseType = typeInfo.BaseType;
        if (baseType != null)
        {
            foreach (var foundType in GetAllImplementedTypes(baseType))
            {
                yield return foundType;
            }
        }
    }
}

このアルゴリズムは、次のシナリオをサポートしています。

public static class GetAllTypesTests
{
    public class Given_A_Sample_Standalone_Class_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        protected override void Given()
        {
            _sut = typeof(SampleStandalone);

            _expectedTypes =
                new List<Type>
                {
                    typeof(SampleStandalone),
                    typeof(object)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    public class Given_A_Sample_Abstract_Base_Class_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        protected override void Given()
        {
            _sut = typeof(SampleBase);

            _expectedTypes =
                new List<Type>
                {
                    typeof(SampleBase),
                    typeof(object)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    public class Given_A_Sample_Child_Class_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        protected override void Given()
        {
            _sut = typeof(SampleChild);

            _expectedTypes =
                new List<Type>
                {
                    typeof(SampleChild),
                    typeof(SampleBase),
                    typeof(object)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    public class Given_A_Sample_Base_Interface_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        protected override void Given()
        {
            _sut = typeof(ISampleBase);

            _expectedTypes =
                new List<Type>
                {
                    typeof(ISampleBase)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    public class Given_A_Sample_Child_Interface_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        protected override void Given()
        {
            _sut = typeof(ISampleChild);

            _expectedTypes =
                new List<Type>
                {
                    typeof(ISampleBase),
                    typeof(ISampleChild)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    public class Given_A_Sample_Implementation_Class_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        protected override void Given()
        {
            _sut = typeof(SampleImplementation);

            _expectedTypes =
                new List<Type>
                {
                    typeof(SampleImplementation),
                    typeof(SampleChild),
                    typeof(SampleBase),
                    typeof(ISampleChild),
                    typeof(ISampleBase),
                    typeof(object)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    public class Given_A_Sample_Interface_Instance_Type_When_Getting_All_Types
        : Given_When_Then_Test
    {
        private Type _sut;
        private IEnumerable<Type> _expectedTypes;
        private IEnumerable<Type> _result;

        class Foo : ISampleChild { }

        protected override void Given()
        {
            var foo = new Foo();
            _sut = foo.GetType();

            _expectedTypes =
                new List<Type>
                {
                    typeof(Foo),
                    typeof(ISampleChild),
                    typeof(ISampleBase),
                    typeof(object)
                };
        }

        protected override void When()
        {
            _result = _sut.GetAllTypes();
        }

        [Fact]
        public void Then_It_Should_Return_The_Right_Type()
        {
            _result.Should().BeEquivalentTo(_expectedTypes);
        }
    }

    sealed class SampleStandalone { }
    abstract class SampleBase { }
    class SampleChild : SampleBase { }
    interface ISampleBase { }
    interface ISampleChild : ISampleBase { }
    class SampleImplementation : SampleChild, ISampleChild { }
}

0
   public IList<T> GetClassByType<T>()
   {
        return AppDomain.CurrentDomain.GetAssemblies()
                          .SelectMany(s => s.GetTypes())
                          .ToList(p => typeof(T)
                          .IsAssignableFrom(p) && !p.IsAbstract && !p.IsInterface)
                          .SelectList(c => (T)Activator.CreateInstance(c));
   }

0

linqコードで例外が発生したため、次のようにします(複雑な拡張なし)。

private static IList<Type> loadAllImplementingTypes(Type[] interfaces)
{
    IList<Type> implementingTypes = new List<Type>();

    // find all types
    foreach (var interfaceType in interfaces)
        foreach (var currentAsm in AppDomain.CurrentDomain.GetAssemblies())
            try
            {
                foreach (var currentType in currentAsm.GetTypes())
                    if (interfaceType.IsAssignableFrom(currentType) && currentType.IsClass && !currentType.IsAbstract)
                        implementingTypes.Add(currentType);
            }
            catch { }

    return implementingTypes;
}

-3

LINQを使用してリストを取得できます。

var types = from type in this.GetType().Assembly.GetTypes()
            where type is ISomeInterface
            select type;

しかし、本当に、それはもっと読みやすいですか?


6
うまくいったなら、もっと読みやすいかもしれません。残念ながら、where句は、System.TypeクラスのインスタンスがISomeInterfaceを実装しているかどうかを確認しています。ただし、ISomeInterfaceが実際にIReflectまたはICustomAttributeProviderである場合を除き、これは常にtrueになります。
Joel Mueller、

上記のCarl Nayakの回答には、where句を修正するための回答があります:IsAssignableFrom。答えの簡単な間違い。
TamusJRoyce、2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.