实例化实现特定接口的所有类

时间:2011-02-25 17:40:13

标签: c# reflection

我有一个接口IExample,以及一组类ClassOneClassTwoClassThree,它们都在不同的名称空间中定义。我可能会删除其中一个类,或者在开发的后期添加一个新类。

现在,我想找到在运行时实现IExample的所有类型,并实例化它们。 (我事先知道实现IExample的类不需要任何构造函数参数,但我不知道如何在代码中指定它,所以它是我 - 而不是编译器 - 知道...)

这可能吗?我该如何去做?

更新:我现在尝试了几种建议的方法,但是对于所有这些方法,Activator.CreateInstance(type)行,我得到一个System.MissingMethodException,因为我“无法创建实例界面。“这是我的代码:

var tasks = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(a => a.GetTypes())
    .Where(t => typeof(IBootstrapperTask).IsAssignableFrom(t))

    // This line is where it fails
    .Select(t => Activator.CreateInstance(t) as IBootstrapperTask)

    .ToArray();
new AutoMapperBootstrapper(tasks).Initialize();

没有as子句我没有看到任何异常,但我得到了object[],我需要IBootstrapperTask[]作为摘录最后一行的构造函数。我尝试了各种方法来投射它,但似乎都没有。

4 个答案:

答案 0 :(得分:29)

这可以通过Reflection完成。例如

var interfaceType = typeof(IExample);
var all = AppDomain.CurrentDomain.GetAssemblies()
  .SelectMany(x => x.GetTypes())
  .Where(x => interfaceType.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
  .Select(x => Activator.CreateInstance(x));

注意:这只会在当前IExample中加载的程序集中创建AppDomain的实例。这可能与当前进程中加载​​的所有程序集不同。但是对于许多类型的应用程序,这将是等效的。

答案 1 :(得分:8)

您需要知道要查看的程序集列表,但LINQ使它相对容易:

var instances = (from assembly in assemblies
                 from type in assembly
                 where !type.IsAbstract && 
                       type.IsClass &&
                       type.IsPublic &&
                       !type.IsGenericType &&
                       typeof(IExample).IsAssignableFrom(type)
                 let ctor = type.GetConstructor(Type.EmptyTypes)
                 where ctor != null && ctor.IsPublic
                 select (IExample) Activator.CreateInstance(type))
                .ToList();

您可能会想到要添加的其他一些限制,但它们很容易表达:)

instances将成为List<IExample>

编辑:我怀疑我的代码会在你没有的地方工作,因为我特意排除非课程。我的猜测是你的代码试图实例化接口本身,即当ttypeof(IBootstrapperTask)时。

答案 2 :(得分:5)

你需要动态发生吗?有没有时候你可能有一个你不想创建的?在我看来,这是依赖注入(可以配置)的一个很好的例子。例如,Unity有一个ResolveAll方法。

从上面的链接;

IEnumerable<IMyObject> objects = myContainer.ResolveAll<IMyObject>();

答案 3 :(得分:0)

尝试使用反射来获取实现IExample的类型。此示例查看当前程序集,但您可以轻松地传递不同的程序集:

        IEnumerable<Type> types = Assembly.GetExecutingAssembly()
            .GetTypes().Where(t=>t.GetInterfaces().Where(tt==typeof(IExample)).Count()>0);
        List<object> objects = new List<object>();
        foreach (Type type in types)
        {
            objects.Add(Activator.CreateInstance(type));
        }