使用 StructureMap 获取继承自基类、实现接口的类型实例

发布于 2024-08-30 14:05:16 字数 790 浏览 7 评论 0原文

为了继续寻求良好的插件实现,我一直在测试 StructureMap 程序集扫描功能。

所有插件都将从抽象类PluginBase继承。这将提供对常见应用程序服务(例如日志记录)的访问。根据其功能,每个插件可能会实现其他接口,例如 IStartUpTask。

我正在像这样初始化我的插件:

            Scan(x => {
            x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"),
                assembly => assembly.GetName().Name.Contains("Extension"));             
            x.AddAllTypesOf<PluginBase>();
        });

然后我遇到的困难是如何在代码中针对接口(而不是 PluginBase)进行工作。使用PluginBase 非常容易:

            var plugins = ObjectFactory.GetAllInstances<PluginBase>();

        foreach (var plugin in plugins)
        {

        }

但是特定功能(例如IStartUpTask.RunTask)与接口相关,而不是与基类相关。

我理解这可能不是特定于结构图的(也许更多的是反射问题)。

谢谢, 本

Continuing on my quest for a good plugin implementation I have been testing the StructureMap assembly scanning features.

All plugins will inherit from abstract class PluginBase. This will provide access to common application services such as logging. Depending on it's function, each plugin may then implement additional interfaces, for example, IStartUpTask.

I am initializing my plugins like so:

            Scan(x => {
            x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"),
                assembly => assembly.GetName().Name.Contains("Extension"));             
            x.AddAllTypesOf<PluginBase>();
        });

The difficulty I am then having is how to work against the interface (not the PluginBase) in code. It's easy enough to work with PluginBase:

            var plugins = ObjectFactory.GetAllInstances<PluginBase>();

        foreach (var plugin in plugins)
        {

        }

But specific functionality (e.g. IStartUpTask.RunTask) is tied to the interface, not the base class.

I appreciate this may not be specific to structuremap (perhaps more a question of reflection).

Thanks,
Ben

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

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

发布评论

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

评论(2

我做我的改变 2024-09-06 14:05:16

注册时的具体接口你都知道吗?如果是这样,您可以制定自定义注册约定,使用其实现的接口的插件“系列”注册每种类型。 IRegistrationConvention 一次获取每种类型。您可以做一个简单的检查来查看当前类型是否实现了所需的接口,如果是,则添加它。

if (typeof(IStartUpTask).IsAssignableFrom(currentType)){
  For<IStartUpTask>().Add(currentType);
}

然后在代码的后面,您可以单独检索每个特定接口的插件:

var startupTasks = ObjectFactory.GetAllInstances<IStartUpTask>();

这种方法的好处是允许您将可枚举的自定义接口插件注入到需要它们的类中,而不是进行服务位置调用。

或者,如果您不想进行注册约定,则可以使用方便的 OfType linq 扩展方法在运行时进行过滤:

var startupTasks = ObjectFactory.GetAllInstances<PluginBase>().OfType<IStartupTask>();

Do you know all of the specific interfaces at registration time? If so, you can make a custom registration convention that registers each type with the plugin "family" of the interface it implements. An IRegistrationConvention gets each type, one at a time. You could do a simple check to see if the current type implements the desired interface, and if so, add it.

if (typeof(IStartUpTask).IsAssignableFrom(currentType)){
  For<IStartUpTask>().Add(currentType);
}

Then later in the code, you can retrieve plugins for each specific interface individually:

var startupTasks = ObjectFactory.GetAllInstances<IStartUpTask>();

This approach has the benefit of allowing you to inject an enumerable of your custom interface plugins into a class that needs them, instead of making the service location call.

Alternatively, if you don't want to make a registration convention, you can just do the filtering at runtime using the handy OfType linq extension method:

var startupTasks = ObjectFactory.GetAllInstances<PluginBase>().OfType<IStartupTask>();
も星光 2024-09-06 14:05:16

为了防止对其他人有帮助,我遵循了 Joshua 的建议并添加了自己的注册约定:

public class PluginConvention : IRegistrationConvention
{
    public void Process(Type type, Registry registry) {
        if (type.BaseType == null) return;

        if (type.BaseType.Equals(typeof(PSAdmin.Core.Domain.PluginBase))) {
            if (typeof(IStartUpTask).IsAssignableFrom(type)) {
                registry.For<IStartUpTask>()
                    .TheDefault.Is.OfConcreteType(type);
            }
        }
    }
}

无论我尝试什么,我都无法使 .Add 方法正常工作,因此必须使用 TheDefault.Is.OfConcreteType(type)。

然后在我的引导程序中,我像这样进行扫描:

        Scan(x => {
            x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"), 
                assembly => assembly.GetName().Name.Contains("Extension"));
            x.Convention<PluginConvention>();
        });

然后我可以像这样获取我的 IStartUp 任务类型:

        var plugins = ObjectFactory.GetAllInstances<IStartUpTask>();              

        foreach (var plugin in plugins)
        {
            plugin.Configure();
        }

也就是说,在阅读了 StructureMap 的一些新功能后,我不确定是否需要执行上述任何操作。例如,我可以将我的 Scan 委托函数更改为:

        Scan(x => {
            x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"),
                assembly => assembly.GetName().Name.Contains("Extension"));
            x.AddAllTypesOf<PluginBase>();
        });

并使用我的接口具体类型(从 PluginBase 继承):

        var tasks = ObjectFactory.Model.GetAllPossible<IStartUpTask>();

        foreach (var task in tasks)
        {
            task.Configure();
        }

两种方法似乎都实现了相同的目标。

In case it helps others, I followed Joshua's advice and added my own registration convention:

public class PluginConvention : IRegistrationConvention
{
    public void Process(Type type, Registry registry) {
        if (type.BaseType == null) return;

        if (type.BaseType.Equals(typeof(PSAdmin.Core.Domain.PluginBase))) {
            if (typeof(IStartUpTask).IsAssignableFrom(type)) {
                registry.For<IStartUpTask>()
                    .TheDefault.Is.OfConcreteType(type);
            }
        }
    }
}

I couldn't get the .Add method to work, no matter what I tried, so had to use TheDefault.Is.OfConcreteType(type).

Then in my bootstrapper I am scanning like so:

        Scan(x => {
            x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"), 
                assembly => assembly.GetName().Name.Contains("Extension"));
            x.Convention<PluginConvention>();
        });

I can then grab my IStartUp task types like so:

        var plugins = ObjectFactory.GetAllInstances<IStartUpTask>();              

        foreach (var plugin in plugins)
        {
            plugin.Configure();
        }

That said, after reading up on some of the new features of StructureMap, I'm not sure I need to do any of the above. For example I could just change my Scan delegate function to:

        Scan(x => {
            x.AssembliesFromPath(HttpContext.Current.Server.MapPath("~/Plugins"),
                assembly => assembly.GetName().Name.Contains("Extension"));
            x.AddAllTypesOf<PluginBase>();
        });

And to use my interface concrete types (that inherit from PluginBase):

        var tasks = ObjectFactory.Model.GetAllPossible<IStartUpTask>();

        foreach (var task in tasks)
        {
            task.Configure();
        }

Both methods seem to achieve the same thing.

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