Programming

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

procodes 2020. 2. 11. 22:44
반응형

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


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

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

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

내 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.

이것은 나를 위해 일했습니다. 클래스를 반복하고 myInterface에서 파생되었는지 확인합니다.

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

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 유형이 다시 표시됩니다.


이 질문은 매우 오래된 질문이지만, 현재까지의 모든 답변은 어떤 형태의를 사용하므로 향후 사용자를위한 또 다른 답변을 추가 할 것이라고 생각했습니다 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();
}

여기에 다른 답변이 사용 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();
}

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


로드 된 모든 어셈블리를 반복하고 모든 유형을 반복하고 인터페이스를 구현하는지 확인합니다.

같은 :

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
        }
    }
}

이것은 나를 위해 일했습니다 (원하는 경우 시스템 유형을 조회에서 제외 할 수 있음).

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

편집 : 방금 원래 질문이 반복 / 코드 축소에 대한 것이고 운동으로 훌륭하고 훌륭하다는 것을 분명히하기 위해 편집을 보았습니다. 그러나 실제 상황에서는 가장 빠른 구현을 원할 것입니다. 기본 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;
}

예쁘지 않아요 인정 할게요


다른 답변은 일반 인터페이스에서 작동하지 않았습니다 .

이것은 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();

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


수행하려는 작업을 수행하는 쉬운 방법은 없습니다 (성능 측면에서).

리플렉션은 주로 어셈블리 및 유형과 함께 작동하므로 모든 유형의 어셈블리를 가져 와서 올바른 인터페이스를 쿼리해야합니다. 예를 들면 다음과 같습니다.

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

어셈블리 MyAssembly에서 IMyInterface를 구현하는 모든 유형을 얻을 수 있습니다.


조립 위치를 선택할 때 더 좋습니다. 구현 된 모든 인터페이스가 동일한 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 작성


   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));
   }

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;
}

LINQ를 사용하여 목록을 얻을 수 있습니다.

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

그러나 실제로 더 읽기 쉬운가?

참고 URL : https://stackoverflow.com/questions/26733/getting-all-types-that-implement-an-interface



반응형