如何查找实现给定接口的所有类?

73
在一个给定的命名空间下,我有一组实现接口的类。我们称之为ISomething。我有另一个类(我们称之为CClass),它知道ISomething,但不知道实现该接口的类。
我希望CClass查找所有ISomething的实现,实例化一个实例并执行方法。
有没有人知道如何在C# 3.5中实现这个功能?

2
可能是使用C# 3.0获取实现接口的所有类型的重复问题。 - Keith Pinson
6个回答

140
一个可用的代码示例:
var instances = from t in Assembly.GetExecutingAssembly().GetTypes()
                where t.GetInterfaces().Contains(typeof(ISomething))
                         && t.GetConstructor(Type.EmptyTypes) != null
                select Activator.CreateInstance(t) as ISomething;

foreach (var instance in instances)
{
    instance.Foo(); // where Foo is a method of ISomething
}

编辑 添加了一个检查无参构造函数的条件,以确保调用CreateInstance方法成功。


9
建议微调一下——使用Type.EmptyTypes而不是实例化一个新的空Type数组。 - Dustin Campbell
有没有一种方法可以在所有已加载的程序集中执行此操作? - gregmac
14
不用管它..var instances = 从当前应用程序域的程序集中获取类型,获取实现了ISomething接口且拥有无参构造函数的类型,并通过Activator.CreateInstance创建实例并转换为ISomething类型。 - gregmac
不错!自从我开始使用MEF以来,我就没有尝试过那个了。 :) - Matt Hamilton
我有一个代码片段,它只使用了老式的反射技术,但这种方式要好得多。 - Brian MacKay
+1 Matt - 这个很好,虽然有点晚了。我特别喜欢这个与gregmac的补充的结合,非常有效。 - jim tollan

11

你可以使用以下代码获取已加载的程序集列表:

Assembly assembly = System.Reflection.AppDomain.CurrentDomain.GetAssemblies()

从那里,您可以获取程序集中类型列表(假设是公共类型):

Type[] types = assembly.GetExportedTypes();

然后你可以通过在对象上查找该接口来询问每种类型是否支持该接口:

Type interfaceType = type.GetInterface("ISomething");

不确定是否有更有效的使用反射来完成此操作的方法。


9

一个使用Linq的例子:

var types =
  myAssembly.GetTypes()
            .Where(m => m.IsClass && m.GetInterface("IMyInterface") != null);

3
foreach (Type t in Assembly.GetCallingAssembly().GetTypes())
{
    if (t.GetInterface("ITheInterface") != null)
    {
        ITheInterface executor = Activator.CreateInstance(t) as ITheInterface;
        executor.PerformSomething();
    }
}

2
您可以使用以下内容,并根据您的需求进行调整。
var _interfaceType = typeof(ISomething);
var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
var types = GetType().GetNestedTypes();

foreach (var type in types)
{
    if (_interfaceType.IsAssignableFrom(type) && type.IsPublic && !type.IsInterface)
    {
        ISomething something = (ISomething)currentAssembly.CreateInstance(type.FullName, false);
        something.TheMethod();
    }
}

这段代码还有优化的空间,但至少是个开端。


0

也许我们应该走这条路

foreach ( var instance in Assembly.GetExecutingAssembly().GetTypes().Where(a => a.GetConstructor(Type.EmptyTypes) != null).Select(Activator.CreateInstance).OfType<ISomething>() ) 
   instance.Execute(); 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接