인터페이스를 구현하는 모든 유형 얻기


553

리플렉션을 사용하면 코드가 가장 적고 반복을 최소화하면서 C # 3.0 / .NET 3.5로 인터페이스를 구현하는 모든 유형을 어떻게 얻을 수 있습니까?

이것은 다시 작성하고 싶습니다.

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

1
예제 코드가 작동합니까? 귀하의 if 상태에 대해 잘못된 부정이 있습니다.
오리온 황제

3
Type 클래스 (t)의 인스턴스가 Type이 IMyInterface를 상속받지 않는 한 인터페이스를 구현하는지 테스트하는 경우 위의 코드의 if 문은 항상 false입니다 (이 경우 항상 true 임).
Liazy 2016 년

답변:


806

내 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

39
참고 :이 답변이 잘못되었습니다! 인터페이스의 구현 여부가 아닌 "지정 호환성"을 확인합니다. 예를 들어 List<string>구현하지 IEnumerable<object>않지만이 메서드는 실제로 잘못된 공분산으로 인해 .Net 4.0에서 true를 반환합니다. 정답은 여기에 있습니다
Sriram Sakthivel

20
@SriramSakthivel은 먼저 일반 값이 지정되지 않았습니다. 둘째,이 질문은 공분산보다 먼저 시작됩니다. 셋째, 공변량 리턴이 원하는 것이 아니라고 가정합니다.
Darren Kopp

24
당신은 절대적으로 맞습니다, 나는 이것이 오래된 스레드라는 것을 알고 있습니다. 나는 미래의 사용자가 그러한 문제가 있음을 알 수 있도록 단지 내 의견을 등록했습니다. 당신을 화나게하지 마십시오. 질문 제목에 따르면 OP가 인터페이스를 구현하는 모든 유형 을 가져 오기를 요청 하면 이 코드는 그렇지 않습니다. 그러나 거의 모든 경우 가 작동합니다 . 내가 말했듯이 코너 케이스도 있습니다. 그냥 알고
Sriram Sakthivel

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
어셈블리가 기본 실행 파일에 있다고 가정합니다. 추가 프로젝트가 아닙니다. 또한 많은 반복을 불필요하게 반복하고 있습니다. 프레임 워크가 무거운 물건을 들어 올리는 것이 좋습니다. 그런 다음 발견되면 더 아래로 필터링하십시오. 관련이 있으면 답변을 업데이트하십시오. List <T> 추론을 포함하십시오. var classTypesImplementingInterface = AppDomain.CurrentDomain.GetAssemblies (). SelectMany (x => x.GetTypes ()). Where (mytype => typeof (myInterface) .IsAssignableFrom (mytype) && mytype.GetInterfaces (). Contains (typeof (myInterface) )); foreach (항목의 var 항목) Console.Log (item.Name);
TamusJRoyce

58

IFoo 인터페이스를 구현하는 어셈블리에서 모든 유형을 찾으려면

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

Ryan Rinaldi의 제안이 잘못되었습니다. 0 유형을 반환합니다. 당신은 쓸 수 없습니다

where type is IFoo

type은 System.Type 인스턴스이고 IFoo 유형이 아니기 때문입니다. 대신 유형에서 IFoo를 할당 할 수 있는지 확인합니다. 예상 결과를 얻을 수 있습니다.

또한 현재 답변으로 표시되어있는 Adam Wright의 제안도 똑같은 이유로 잘못되었습니다. 모든 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 : 요청 된 유형 중 하나 이상을로드 할 수 없습니다. 자세한 정보는 LoaderExceptions 특성을 검색하십시오. 더 구체적으로 말하면 구체적인 구현이없는 유형이 있었고 단위 테스트 프로젝트에서 발생했다고 불평했습니다. 감사합니다!
Lari Tuomisto

2
우리가 수없는이 답변이 솔루션으로 표시해야 @Lari Tuomisto 말했듯이 있기 때문에,이 지역 ENV에, 오늘 내 엉덩이 저장된 다시 제품과 유사한 오류
Lightning3

3
다른 사람에게 도움이되는 경우 :이 솔루션은 저에게 효과적이지만 목록에서 인터페이스 유형을 제거하도록 수정해야했습니다. 나는 CreateInstance그들 모두 를 활성화 하고 싶었고 실제 인터페이스를 만들려고 할 때 예외가 발생했습니다 (실제 인터페이스 가이 솔루션에서 길을 벗어났다고 생각했을 때 잠시 혼란 스러웠습니다). 그래서 코드를로 변경했습니다 GetLoadableTypes(assembly).Where(interfaceType.IsAssignableFrom).Where(t => !(t.Equals(interfaceType))).ToList();.
Xavier Peña

21

여기에 다른 답변이 사용 IsAssignableFrom됩니다. 여기에 설명 된대로 네임 스페이스 FindInterfaces에서 사용할 수도 있습니다 .System

다음은 현재 실행중인 어셈블리 폴더의 모든 어셈블리를 검사하여 특정 인터페이스를 구현하는 클래스를 찾는 예입니다 (명확성을 위해 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();
}

둘 이상의 인터페이스를 일치 시키려면 인터페이스 목록을 설정할 수 있습니다.


이것은 내가 찾던 문자열 인터페이스 이름을 찾습니다.
senthil

형식을 문자열로 직렬화해야하므로 다른 도메인에서 어셈블리를로드 할 때 작동합니다. 굉장 해요!
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 옵션은 자체 / 타사 코드베이스에서 구현을 찾고 있다면 작업 속도를 크게 향상시킵니다.

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을 구현합니다. foreach 또는 linq를 사용하는 것이 좋습니다.
TamusJRoyce

excludeSystemTypes한 번에 두 번 테스트 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();

그것들을 목록에 넣으십시오.


솔루션의 작동 방식과 다른 모든 솔루션보다 우수한 이유를 설명하십시오.
Lukas Körfer

그것은 우수하지 않거나 낮지 않습니다. 다른 답변은 저에게 효과가 없었으며 그것을 공유하기를 귀찮게했습니다.
Antonin GAVREL

내 의견은 코드 전용 답변에 관한 것이므로 설명을 추가하도록 요청했습니다.
Lukas Körfer

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를 구현하는지 확인합니다.
Joel Mueller

위의 Carl Nayak 답변에는 where 절 수정에 대한 답변이 있습니다 : IsAssignableFrom. 대답하기 쉬운 실수.
TamusJRoyce
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.