获取实现接口的所有类型

Getting all types that implement an interface

提问人:juan 提问时间:8/26/2008 最后编辑:Ondrej Janacekjuan 更新时间:4/11/2023 访问量:383198

问:

使用反射,如何以最少的代码获取实现 C# 3.0/.NET 3.5 接口的所有类型,并最大限度地减少迭代?

这是我想重写的:

foreach (Type t in this.GetType().Assembly.GetTypes())
    if (t is IMyInterface)
        ; //do stuff
C 优化 反射 lambda C#-3.0

评论

1赞 Emperor Orionii 12/15/2012
示例代码是否有效?我对你的 if 条件有假阴性。
5赞 Liazy 6/26/2013
上面代码中的 if 语句将始终为 false,因为您正在测试 Type 类 (t) 的实例是否实现了您的接口,除非 Type 继承了 IMyInterface(在这种情况下,它将始终为 true),否则它不会实现您的接口。

答:

18赞 Lasse V. Karlsen 8/26/2008 #1

循环遍历所有已加载的程序集,遍历其所有类型,并检查它们是否实现接口。

像这样:

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
        }
    }
}
945赞 Darren Kopp 8/26/2008 #2

我的在 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.

评论

255赞 jtpereyda 12/3/2013
请注意,该列表还可能包括接口本身。将最后一行更改为 以将其过滤掉(或 )。.Where(p => type.IsAssignableFrom(p) && !p.IsInterface);p.IsClass
50赞 Sriram Sakthivel 4/8/2014
注意:这个答案是错误的!,这个检查的是“赋值兼容性”,而不是接口是否实现。例如,没有实现,但由于协方差,此方法将在 .Net 4.0 中返回 true,这确实是错误的。正确答案在这里List<string>IEnumerable<object>
25赞 Darren Kopp 4/8/2014
@SriramSakthivel首先,未指定泛型值。其次,这个问题早于协方差。第三,你假设协变返回不是他们想要的。
32赞 Sriram Sakthivel 4/9/2014
你是绝对正确的,达伦,我知道这是一个旧线程,我只是注册了我的评论,只是为了让未来的用户意识到这个问题的存在。不要冒犯你。正如问题标题所说,如果 OP 要求获取实现接口的所有类型,则此代码不会这样做。但毫无疑问,几乎所有情况下它都有效。正如我所说,也有极端情况。只是为了意识到这一点;
23赞 Jonesopolis 12/24/2015
还需要确保该类不是抽象的 =>.Where(p => type.IsAssignableFrom(p) && p.IsClass && !p.IsAbstract
4赞 tags2k 8/26/2008 #3

编辑:我刚刚看到编辑以澄清最初的问题是减少迭代/代码,这是一个很好的练习,但在现实世界中,您将需要最快的实现,无论底层 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赞 TamusJRoyce 5/20/2015
枚举器实现 IDisposable,它不会在 try/finally 中释放。最好使用 foreach 或 linq。
1赞 NetMage 12/12/2019
你为什么要一次测试两次?excludeSystemTypesif
3赞 Jorge Córdoba 8/26/2008 #4

没有简单的方法(就性能而言)来做你想做的事情。

反射主要使用程序集和类型,因此您必须获取程序集的所有类型,并查询它们以获取正确的接口。下面是一个示例:

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

这将为您提供在程序集 MyAssembly 中实现 IMyInterface 的所有类型

-4赞 Ryan Rinaldi 8/26/2008 #5

您可以使用一些 LINQ 来获取列表:

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

但实际上,这更具可读性吗?

评论

6赞 Joel Mueller 5/30/2009
如果它有效,它可能更具可读性。遗憾的是,where 子句正在检查 System.Type 类的实例是否实现 ISomeInterface,这永远不会为 true,除非 ISomeInterface 确实是 IReflect 或 ICustomAttributeProvider,在这种情况下,它将始终为 true。
0赞 TamusJRoyce 5/20/2015
上面的 Carl Nayak 答案有更正 where 子句的答案:IsAssignableFrom。答案很容易出错。
66赞 Judah Gabriel Himango 8/26/2008 #6

若要在实现 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)的建议(目前被标记为答案)也是不正确的,原因相同。在运行时,你将看到 0 个类型返回,因为所有 System.Type 实例都不是 IFoo 实现器。

评论

0赞 Petter Pettersson 4/22/2021
这是正确答案。公认的答案不起作用。
0赞 JP Garza 10/23/2021
这也返回接口本身。看起来这个问题只要求返回继承接口的类类型,而不是接口本身。最好。
0赞 Paul Rouleau 2/2/2023
同意。这是正确答案。另外,由于我喜欢 lambda 语法,因此可以将其编写为 var results = assembly。GetTypes() 中。其中 (t => typeof(IFoo)。IsAssignableFrom(t)) 中。选择(t => t)。ToList();
12赞 Carl Nayak 11/12/2010 #7

这对我有用(如果您愿意,可以在查找中排除系统类型):

Type lookupType = typeof (IMenuItem);
IEnumerable<Type> lookupTypes = GetType().Assembly.GetTypes().Where(
        t => lookupType.IsAssignableFrom(t) && !t.IsInterface); 
23赞 hillstuk 6/8/2012 #8

此处的其他答案使用 .您也可以从命名空间使用,如此处所述。IsAssignableFromFindInterfacesSystem

下面是一个示例,该示例检查当前正在执行的程序集文件夹中的所有程序集,查找实现特定接口的类(为清楚起见,请避免使用 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();
}

如果要匹配多个接口,可以设置接口列表。

评论

0赞 senthil 1/10/2013
这个寻找字符串接口名称,这就是我一直在寻找的。
0赞 TamusJRoyce 5/20/2015
在不同域中加载程序集时起作用,因为必须将类型序列化为字符串。太棒了!
0赞 bkwdesign 10/4/2019
我得到:无法解析对程序集“System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”的依赖关系,因为它尚未预加载。使用 ReflectionOnly API 时,必须通过 ReflectionOnlyAssemblyResolve 事件预加载或按需加载依赖程序集。
95赞 Ben Watkins 9/26/2012 #9

这对我有用。它遍历这些类并检查它们是否是从 myInterface 派生而来的

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

评论

8赞 TamusJRoyce 8/29/2014
假定程序集位于主可执行文件中。不是额外的项目。您也在通过一堆迭代进行不必要的迭代。最好让框架来完成繁重的工作。然后在发现时进一步过滤。如果相关,请更新您的答案。包括 List<T> 推理。var classTypesImplementingInterface = AppDomain.CurrentDomain.GetAssemblies()。选择Many(x => x.GetTypes())。其中 (mytype => typeof(myInterface)。IsAssignableFrom(mytype) 和 & mytype。GetInterfaces() 中。包含(typeof(myInterface)));foreach(var item in items) Console.Log(item.姓名);
0赞 eternal_frame 5/5/2023
这对我有用,即使我的组装在一个额外的项目中。但是,它让我陷入困境,因此,如果以后真的想实际转换为该接口,使用可能会更安全。InvalidCastException.IsAssignableFrom(..)
83赞 rism 4/1/2015 #10

其他答案使用某种形式的 Assembly.GetTypes

虽然 GetTypes() 确实会返回所有类型,但这并不一定意味着您可以激活它们,因此可能会抛出 ReflectionTypeLoadException

无法激活类型的一个典型示例是,当返回的类型来自 的程序集,但在与调用程序集不引用的程序集不同的程序集中定义时。derivedbasebasederived

所以假设我们有:

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

如果在哪个,我们按照公认的答案做一些事情:ClassCAssemblyC

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 的这篇文章 Get All Types in an AssemblyJon 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();
}

评论

4赞 Lari Tuomisto 11/18/2015
这帮助我处理了一个超级奇怪的问题,在我的测试项目中,GetTypes 会失败,并且仅在我们的 CI 环境中失败。GetLoadableTypes 是此解决方案的修复程序。该错误在本地环境中无法重现,如下所示:System.Reflection.ReflectionTypeLoadException:无法加载一个或多个请求的类型。检索 LoaderExceptions 属性以获取更多信息。更具体地说,它抱怨有一种类型没有具体的实现,它发生在单元测试项目中。谢谢你!
2赞 Lightning3 12/30/2015
这个答案应该标记为解决方案,它今天救了我的屁股,因为就像 @Lari Tuomisto 所说的那样,在本地环境中,我们无法重新产生类似的错误
4赞 Xavier Peña 8/8/2016
万一它对其他人有帮助:这个解决方案对我有用,但我不得不修改它以从列表中删除接口类型。我想为所有这些激活,当它尝试创建实际界面时抛出了一个异常(当我认为实际界面在这个解决方案中不碍事时,这让我感到困惑了一段时间)。所以我把代码改成了.CreateInstanceGetLoadableTypes(assembly).Where(interfaceType.IsAssignableFrom).Where(t => !(t.Equals(interfaceType))).ToList();
0赞 akop 2/27/2018 #11

我在 linq-code 中遇到了异常,所以我这样做(没有复杂的扩展):

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;
}
11赞 Antonin GAVREL 9/20/2018 #12

其他答案是不适用于通用接口

这个确实如此,只需将 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();

将它们放在列表中。

评论

0赞 Lukas Körfer 9/20/2018
请解释您的解决方案是如何工作的,以及为什么它优于所有其他答案。
0赞 Antonin GAVREL 9/20/2018
它没有优越或更低,其他答案对我不起作用,我费心分享它。
0赞 Lukas Körfer 9/20/2018
我的评论只是关于你的答案是纯代码的,所以我要求你添加一些解释。
4赞 user489566 1/22/2019 #13

在选择组装位置时会更好。如果您知道所有已实现的接口都位于同一 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赞 Jonathan Santiago 8/5/2019 #14
   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赞 Hamdi Baligh 3/25/2020 #15

OfType Linq 方法可以完全用于此类方案:

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

1赞 diegosasw 3/31/2020 #16

已经有很多有效的答案,但我想添加另一个实现作为类型扩展和单元测试列表来演示不同的场景:

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 { }
}
9赞 rvnlord 8/2/2020 #17

我在这里看到了很多过于复杂的答案,人们总是告诉我,我倾向于把事情复杂化。此外,使用方法来解决OP问题也是错误的!IsAssignableFrom

这是我的示例,它从应用程序域中选择所有程序集,然后获取所有可用类型的平面列表,并检查每个类型的接口列表是否匹配:

public static IEnumerable<Type> GetImplementingTypes(this Type itype) 
    => AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes())
           .Where(t => t.GetInterfaces().Contains(itype));
6赞 chtenb 4/1/2021 #18

到目前为止,发布的所有答案要么考虑了太少的程序集,要么考虑了太多的程序集。只需检查引用包含接口的程序集的程序集。这最大限度地减少了不必要地运行的静态构造函数的数量,并节省了大量时间,并在第三方程序集的情况下节省了可能出现的意外副作用。

public static class ReflectionUtils
{
    public static bool DoesTypeSupportInterface(Type type, Type inter)
    {
        if (inter.IsAssignableFrom(type))
            return true;
        if (type.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == inter))
            return true;
        return false;
    }

    public static IEnumerable<Assembly> GetReferencingAssemblies(Assembly assembly)
    {
        return AppDomain
            .CurrentDomain
            .GetAssemblies().Where(asm => asm.GetReferencedAssemblies().Any(asmName => AssemblyName.ReferenceMatchesDefinition(asmName, assembly.GetName())));
    }

    public static IEnumerable<Type> TypesImplementingInterface(Type desiredType)
    {
        var assembliesToSearch = new Assembly[] { desiredType.Assembly }
            .Concat(GetReferencingAssemblies(desiredType.Assembly));
        return assembliesToSearch.SelectMany(assembly => assembly.GetTypes())
            .Where(type => DoesTypeSupportInterface(type, desiredType));
    }

    public static IEnumerable<Type> NonAbstractTypesImplementingInterface(Type desiredType)
    {
        return TypesImplementingInterface(desiredType).Where(t => !t.IsAbstract);
    }
}
1赞 classicSchmosby98 4/27/2022 #19

如果它对任何人有帮助,这就是我用来使我的一些单元测试更容易:)

public static Type GetInterfacesImplementation(this Type type)
{
    return type.Assembly.GetTypes()
        .Where(p => type.IsAssignableFrom(p) && !p.IsInterface)
        .SingleOrDefault();
}