c# xml - Получение всех типов, реализующих интерфейс




style in (11)

Вы можете использовать LINQ для получения списка:

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

Но действительно ли это более читаемо?

Используя отражение, как я могу получить все типы, которые реализуют интерфейс с C # 3.0 / .NET 3.5 с наименьшим кодом и минимизацию итераций?

Это то, что я хочу переписать:

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

Изменить: я только что видел редактирование, чтобы уточнить, что исходный вопрос был для сокращения итераций / кода, и все это хорошо и хорошо, как упражнение, но в реальных ситуациях вам понадобится самая быстрая реализация, независимо как классно выглядит 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;
}

Соглашусь, это некрасиво.


Это сработало для меня. Он зацикливает на классы и проверки, чтобы убедиться, что они уцелели от myInterface

 foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                 .Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)))) {
    //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.

Другой ответ не работал с общим интерфейсом .

Это делает, просто замените 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();

чтобы они были в списке.


Чтобы найти все типы в сборке, которые реализуют интерфейс IFoo:

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

Обратите внимание, что предложение Райана Ринальди было неправильным. Он вернет 0 типов. Вы не можете писать

where type is IFoo

потому что тип является экземпляром System.Type и никогда не будет иметь тип IFoo. Вместо этого вы проверяете, можно ли назначить IFoo из этого типа. Это даст вам ожидаемые результаты.

Кроме того, предложение Адама Райта, которое в настоящее время отмечено как ответ, неверно и по той же причине. Во время выполнения вы увидите, что возвращается 0 типов, потому что все экземпляры System.Type не были разработчиками IFoo.


Это сработало для меня (если вы хотите, чтобы вы могли исключать типы систем в поиске):

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

Другие ответы здесь используют IsAssignableFrom . Вы также можете использовать FindInterfaces из пространства имен System , как описано here .

Вот пример, который проверяет все сборки в папке текущей исполняемой сборки, ища классы, реализующие определенный интерфейс (для ясности избегаем 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();
}

Вы можете настроить список интерфейсов, если вы хотите совместить несколько.


Я ценю, что это очень старый вопрос, но я думал, что добавлю еще один ответ будущим пользователям, поскольку все ответы на сегодняшний день используют некоторую форму 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 .

Это связано с тем, что без ссылки на AssemblyA в AssemblyC вы не сможете:

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

Другими словами, ClassB не загружается, что-то, что вызов GetTypes проверяет и бросает.

Таким образом, чтобы безопасно квалифицировать набор результатов для загружаемых типов, то согласно этой статье « Фил Хаукед» « Получить все типы в сборке» и « Джон Скит» вы вместо этого сделаете что-то вроде:

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

Нет простого способа (с точки зрения производительности) делать то, что вы хотите сделать.

Отражение работает с сборками и типами в основном, поэтому вам нужно будет получить все типы сборки и запросить их для правильного интерфейса. Вот пример:

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

Это даст вам все типы, которые реализуют IMyInterface в сборке MyAssembly


Попробуйте использовать код ниже.

var Item = GetAll().GroupBy(x => x .Id).ToList();






c# optimization reflection lambda c#-3.0