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

发布于 2024-10-19 01:06:45 字数 1008 浏览 1 评论 0原文

我有一个接口 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[ ] 为摘录最后一行的构造函数。我尝试了各种方法来投射它,但似乎都不起作用。

I have an interface IExample, and a set of classes ClassOne, ClassTwo and ClassThree, all defined in different namespaces. I will possibly remove either of the classes, or add a new one in a new place, at a later stage in development.

Now, I want to find all types that implement IExample at runtime, and instantiate them. (I know on beforehand that no class implementing IExample will ever need any constructor arguments, but I don't know how to specify that in code, so it's me - not the compiler - that knows...)

Is this possible? How do I go about to do it?

Update: I've now tried several of the approaches suggested, but on all of them, the line Activator.CreateInstance(type), I get a System.MissingMethodException because I "cannot create an instance of an interface." This is my code:

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

Without the as clause I don't see any exception, but I'm given an object[], and I need an IBootstrapperTask[] for the constructor on the last line in the excerpt. I've tried various ways to cast it, but none seem to work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

深海不蓝 2024-10-26 01:06:45

这可以通过反射来完成。例如,

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

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

This can be done with Reflection. For example

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

Note: This will only create instances of IExample from assemblies loaded in the current AppDomain. This can be different than all assemblies loaded in the current process. However for many types of applications this will be equivalent.

无妨# 2024-10-26 01:06:45

您需要知道要查看的程序集列表,但是 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();

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

实例那么将是一个List

编辑:我怀疑我的代码可以在你的代码不能工作的地方工作,因为我专门排除了非类。我的猜测是,您的代码正在尝试实例化接口本身,即当 ttypeof(IBootstrapperTask) 时。

You'd need to know a list of assemblies to look in, but then LINQ makes it relatively easy:

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

You may think of some other restrictions to add, but they're pretty easy to express :)

instances will then be a List<IExample>.

EDIT: I suspect my code will work where yours didn't, because I'm specifically excluding non-classes. My guess is that your code is trying to instantiate the interface itself, i.e. when t is typeof(IBootstrapperTask).

谢绝鈎搭 2024-10-26 01:06:45

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

来自上面的链接;

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

Do you need this to happen dynamically? Are there ever times when you might have one that you don't want to create? Seems to me that this is a good case for dependency injection (which can be configured). For example Unity has a ResolveAll method .

From the above link;

IEnumerable<IMyObject> objects = myContainer.ResolveAll<IMyObject>();
_蜘蛛 2024-10-26 01:06:45

尝试使用反射来获取实现 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));
        }

Try using reflection to get the types implementing IExample. This example looks at the current assembly but you could easily pass a different assembly:

        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));
        }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文