如何根据存储在属性中的名称使用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类中自动注册类型。
答案 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();
}
}