使用StructureMap按名称创建类?

时间:2010-03-31 22:21:18

标签: dependency-injection structuremap ioc-container

如何根据存储在属性中的名称使用StructureMap来解析接口的适当实现?

在我的项目中,我有许多不同类型的小部件,每个小部件都来自IWidget,每个小部件都使用指定相关元素类型的属性进行装饰。

举例说明:

[Configuration("header")]
public class HeaderWidget : IWidget { }

[Configuration("linegraph")]
public class LineGraphWidget : IWidget { }

处理我的(XML)配置文件时,我想根据我正在处理的元素的名称获取适当的具体类的实例。

public IWidget CreateWidget(XElement definition)
{
    var kind = definition.Name.LocalName;
    var widget = // What goes here?
    widget.Configure(definition);
    return widget;
}

每个定义都应该导致创建不同的小部件 - 我不需要或希望共享实例。

在过去,我已经编写了大量代码来手动完成这类工作,包括为一个项目编写一个自定义的“自己动手”的IoC容器。但是,我在这个项目中的目标之一是熟练使用StructureMap而不是重新发明轮子。

我想我已经设法自动扫描程序集,以便StructureMap知道我所有的IWidget实现:

public class WidgetRegistration : Registry
{
    public WidgetRegistration()
    {
        Scan(
            scanner =>
            {
                scanner.AssembliesFromApplicationBaseDirectory();
                scanner.AddAllTypesOf<IWidget>();
            });
    }
}

但是,这并没有使用StructureMap注册我的小部件的名称。我需要添加什么才能使我的场景有效?

(虽然我试图在这个项目中使用StructureMap,但是一个答案显示如何使用不同的DI / IoC工具解决这个问题仍然很有价值。)

更新

我很确定消费方需要像这样调用GetNamedInstance

public IWidget CreateWidget(XElement definition)
{
    var kind = definition.Name.LocalName;
    var widget = ObjectFactory.GetNamedInstance<IWidget>(kind);
    widget.Configure(definition);
    return widget;
}

因此,剩下的难题是如何在我的WidgetRegistration类中自动注册类型。

2 个答案:

答案 0 :(得分:1)

我们实施了自定义扫描程序:

    public class WidgetScanner : ITypeScanner
{
    public void Process(Type type, PluginGraph graph)
    {

然后使用scan:

        Scan(y =>
        {
            y.AddAllTypesOf(typeof(IWidget));
            y.Assembly(Assembly.GetExecutingAssembly().FullName);
            y.With<WidgetScanner>();
        });

..并获得一个实例:

_container.GetInstance<IWidget>(name)

答案 1 :(得分:1)

这是我最终的结果 - 结果表明我所需要的一切都是开箱即用的。

我的注册课负责处理所有肮脏的工作:

public class DashboardRegistration : Registry
{
    public DashboardRegistration()
    {
        Scan(
            scanner =>
            {
                scanner.AssembliesFromApplicationBaseDirectory();
                scanner.AddAllTypesOf<IDisplay>()
                    .NameBy(DashboardXml.DisplayElement);
                scanner.AddAllTypesOf<IDataSource>()
                    .NameBy(DashboardXml.DataSourceElement);
            });
    }
}

.NameBy()需要一个提供所需名称的委托。

DashboardXml类上的相应方法如下所示(代码删节):

public static class DashboardXml
{
    ...

    public static string DataSourceElement(Type type)
    {
        const string DataSourceSuffix = "DataSource";

        string result = type.Name;
        if (result.EndsWith(DataSourceSuffix))
        {
            result 
                = result.Substring(0, result.Length - DataSourceSuffix.Length);
        }

        return result.ToLowerInvariant();
    }

    public static string DisplayElement(Type type)
    {
        const string DisplaySuffix = "Display";

        string result = type.Name;
        if (result.EndsWith(DisplaySuffix))
        {
            result 
                = result.Substring(0, result.Length - DisplaySuffix.Length);
        }

        return result.ToLowerInvariant();
    }
}