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

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

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

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

Пример кода работает? У меня ложноотрицательные результаты с вашим условием if.

Emperor Orionii 15.12.2012 19:20

Оператор if в приведенном выше коде всегда будет ложным, потому что вы проверяете, реализует ли экземпляр класса Type (t) ваш интерфейс, чего он не будет, если Type не наследует IMyInterface (в этом случае он всегда будет истинным).

Liazy 26.06.2013 16:09
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
593
2
286 928
17
Перейти к ответу Данный вопрос помечен как решенный

Ответы 17

перебрать все загруженные сборки, перебрать все их типы и проверить, реализуют ли они интерфейс.

что-то вроде:

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
        }
    }
}
Ответ принят как подходящий

У меня было бы это в 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.

Обратите внимание, что список может также включать сам интерфейс. Измените последнюю строку на .Where(p => type.IsAssignableFrom(p) && !p.IsInterface);, чтобы отфильтровать ее (или p.IsClass).

jtpereyda 03.12.2013 01:21

Примечание. Этот ответ неверен! Это проверяет «Совместимость назначений», а не реализован ли интерфейс. Например, List<string> не реализует IEnumerable<object>, но этот метод вернет true в .Net 4.0 из-за ковариации, что действительно неверно. Правильный ответ здесь

Sriram Sakthivel 08.04.2014 11:29

@SriramSakthivel во-первых, общие значения не указаны. Во-вторых, этот вопрос предшествует ковариации. В-третьих, вы делаете предположение, что они не хотят ковариантной отдачи.

Darren Kopp 08.04.2014 17:45

Вы абсолютно правы, Даррен, я знаю, что это старая ветка, я только что зарегистрировал свой комментарий, чтобы будущие пользователи знали о существовании такой проблемы. Чтобы не обидеть вас. и, как говорится в заголовке вопроса, если OP запрашивает Получение всех типов, реализующих интерфейс, этот код этого не делает. но почти во всех случаях оно работает, без сомнения. как я уже сказал, есть и угловые случаи. Просто чтобы осознавать это;

Sriram Sakthivel 08.04.2014 20:13

Кроме того, нет необходимости объявлять var type = typeof(IMyInterface), потому что typeof(IMyInterface) оценивается во время компиляции и не повторно оценивается снова и снова в операторе Where.

ErikE 14.08.2015 20:43

Также необходимо убедиться, что класс не абстрактный => .Where(p => type.IsAssignableFrom(p) && p.IsClass && !p.IsAbstract

Jonesopolis 23.12.2015 21:11

@Jonesopolis, задающий вопрос, не указал, хотят ли они создать экземпляр класса. абстрактные классы могут по-прежнему реализовывать интерфейсы и могут быть тем, что вы хотите искать, в зависимости от того, что вы делаете.

Darren Kopp 26.12.2015 00:35

@DarrenKopp хороший звонок. Я только что сделал предположение, что он ищет экземпляры классов, я был, когда нашел этот вопрос.

Jonesopolis 26.12.2015 16:46

убедитесь, что ваша сборка с интерфейсом включена в папку bin, чтобы этот код мог ее подобрать, это была моя проблема

Demodave 21.04.2016 16:21

Я пробовал это для классов, реализующих из Интерфейса. Работает нормально. Но почему это не работает для абстрактного класса?

Avishekh Bharati 23.06.2016 14:31

Добавьте использование: using System;, using System.Reflection и using System.Linq для начинающих.

Hasan Bayat 21.04.2017 11:01

@SriramSakthivel Звучит непонятно, к сожалению, поискав в Google, я ничего не смог найти. Не могли бы вы назвать мне несколько ключевых слов для ковариации, чтобы я мог их найти?

snowflake 21.04.2018 12:31

@snowflake Статья Эрика должна помочь blogs.msdn.microsoft.com/ericlippert/2009/11/30/…. Google с такими ключевыми словами, как "ковариация Эрика Липперта", вы получите много просмотров.

Sriram Sakthivel 21.04.2018 16:50

Я хотел бы добавить, что проверка того, не является ли тип абстрактным, исключает как интерфейсы, так и абстрактные классы, поэтому .Where(p => type.IsAssignableFrom(p) && !p.IsAbstract) должно быть достаточно.

Samuel Cabrera 21.05.2020 13:12

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

Признаюсь, это некрасиво.

Перечислители реализуют IDisposable, который не удаляется в try / finally. Лучше использовать foreach или linq.

TamusJRoyce 20.05.2015 07:09

Почему вы тестируете excludeSystemTypes дважды в одном if?

NetMage 11.12.2019 23:23

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

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

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

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

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

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

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

Он мог бы быть более читабельным, если бы работал. К сожалению, ваше предложение where проверяет, реализует ли экземпляр класса System.Type ISomeInterface, что никогда не будет истинным, если только ISomeInterface действительно не является IReflect или ICustomAttributeProvider, и в этом случае он всегда будет истинным.

Joel Mueller 30.05.2009 00:22

В приведенном выше ответе Карла Наяка есть ответ на исправление предложения where: IsAssignableFrom. Легкая ошибка за ответ.

TamusJRoyce 20.05.2015 07:06

Чтобы найти все типы в сборке, реализующие интерфейс 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, как описано здесь.

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

Работает при загрузке сборки в другом домене, так как тип должен быть сериализован в строку. очень здорово!

TamusJRoyce 20.05.2015 07:12

Я получаю: Не удается разрешить зависимость от сборки «System.Core, Version = 4.0.0.0, Culture = нейтральный, PublicKeyToken = b77a5c561934e089», потому что она не была предварительно загружена. При использовании API ReflectionOnly зависимые сборки должны быть предварительно загружены или загружены по запросу через событие ReflectionOnlyAssemblyResolve.

bkwdesign 03.10.2019 20:06

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

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

Вы предполагаете, что сборка находится в основном исполняемом файле. Не дополнительный проект. Вы также повторяете без необходимости, несмотря на кучу итераций. Лучше, чтобы тяжелая работа выполняла каркас. Затем отфильтруйте дальше, когда найдете. Если уместно, обновите свой ответ. Включить Listрассуждения. var classTypesImplementingInterface = AppDomain.CurrentDomain.GetAssemblies (). SelectMany (x => x.GetTypes ()). Где (mytype => typeof (myInterface) .IsAssignableFrom (mytype) && mytype.GetInterfaces (). my Contains (typeof) )); foreach (var item in items) Console.Log (item.Name);

TamusJRoyce 29.08.2014 06:37

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

Это помогло мне справиться с очень странной проблемой, когда в моем тестовом проекте GetTypes не работал и только в нашей CI-среде. GetLoadableTypes был исправлением для этого решения. Ошибка не могла быть воспроизведена в локальной среде, и это было следующее: System.Reflection.ReflectionTypeLoadException: невозможно загрузить один или несколько запрошенных типов. Получите свойство LoaderExceptions для получения дополнительных сведений. В частности, он жаловался на то, что существует тип, который не имеет конкретной реализации, и это произошло в проекте модульного тестирования. Спасибо за это!

Lari Tuomisto 18.11.2015 10:44

Этот ответ должен быть отмечен как решение, он спас мою задницу сегодня, потому что, как сказал @Lari Tuomisto, на локальном env мы не могли повторно воспроизвести аналогичную ошибку

Lightning3 30.12.2015 02:19

На случай, если это поможет кому-то другому: это решение сработало для меня, но мне пришлось изменить его, чтобы удалить тип интерфейса из списка. Я хотел активировать CreateInstance для всех из них, и возникло исключение, когда он пытался создать реальный интерфейс (что меня на некоторое время смутило, когда я подумал, что реальный интерфейс не в этом решении). Поэтому я изменил код на GetLoadableTypes(assembly).Where(interfaceType.IsAssignableF‌​rom).Where(t => !(t.Equals(interfaceType))).ToList();.

Xavier Peña 07.08.2016 20:38

У меня есть исключения в 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;
}

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

Вот этот, просто замените 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 20.09.2018 00:57

Это не выше или ниже, другие ответы не помогли мне, и я потрудился поделиться ими.

Antonin GAVREL 20.09.2018 11:24

Мой комментарий касался только того, что ваш ответ - это код, поэтому я попросил вас добавить некоторые пояснения.

Lukas Körfer 20.09.2018 11:37

Еще лучше при выборе места сборки. Отфильтруйте большинство сборок, если вы знаете, что все реализованные вами интерфейсы находятся в пределах одного 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();

Автор: Кан Билгин

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

Метод OfType Linq можно использовать именно для таких сценариев:

https://docs.microsoft.com/fr-fr/dotnet/api/system.linq.enumerable.oftype?view=netframework-4.8

Уже есть много правильных ответов, но я хотел бы добавить другую реализацию в виде расширения типа и список модульных тестов для демонстрации различных сценариев:

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

Я вижу здесь так много чрезмерно сложных ответов, и люди всегда говорят мне, что я склонен к чрезмерному усложнению. Также неправильно использовать метод IsAssignableFrom для решения проблемы OP!

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

public static IEnumerable<Type> GetImplementingTypes(this Type itype) 
    => AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes())
           .Where(t => t.GetInterfaces().Contains(itype));

Другие вопросы по теме