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

时间:2010-04-27 10:05:17

标签: reflection inversion-of-control structuremap

继续寻求良好的插件实现,我一直在测试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)与接口绑定,而不是基类。

我很欣赏这可能不是特定于结构图(也许更多的是反思问题)。

谢谢, 本

2 个答案:

答案 0 :(得分:2)

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

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

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

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

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

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

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

答案 1 :(得分:0)

如果它帮助了其他人,我遵循了约书亚的建议并添加了我自己的注册惯例:

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

两种方法似乎都达到了同样的目的。