用AutoFac替换出厂

我习惯于创建我自己的工厂(如图所示):

public class ElementFactory { public IElement Create(IHtml dom) { switch (dom.ElementType) { case "table": return new TableElement(dom); case "div": return new DivElement(dom); case "span": return new SpanElement(dom); } return new PassthroughElement(dom); } } 

我终于开始在我当前的项目中使用IoC容器(AutoFac)了,我想知道是否有一些使用AutoFac优雅地实现同样function的神奇方法?

简短回答:是的。

更长的答案:首先,在Foo类被注册为IFoo实现的简单情况下,构造函数参数或类型为Func属性将由Autofac自动解析,无需额外布线。 Autofac将注入一个委托,该委托在调用时基本上执行container.Resolve()

在像你这样的更复杂的情况下,返回的确切结果是基于输入参数,你可以做两件事之一。 首先,您可以将工厂方法注册为其返回值,以提供参数化分辨率:

 builder.Register((c, p) => { var dom= p.Named("dom"); switch (dom.ElementType) { case "table": return new TableElement(dom); case "div": return new DivElement(dom); case "span": return new SpanElement(dom); } return new PassthroughElement(dom); }); //usage container.Resolve(new NamedParameter("dom", domInstance)) 

这不是类型安全的(domInstance不会被编译器检查以确保它是一个IHtml),也不是很干净。 相反,另一种解决方案是将工厂方法实际注册为Func:

 builder.Register>(dom => { switch (dom.ElementType) { case "table": return new TableElement(dom); case "div": return new DivElement(dom); case "span": return new SpanElement(dom); } return new PassthroughElement(dom); }); public class NeedsAnElementFactory //also registered in AutoFac { protected Func CreateElement {get; private set;} //AutoFac will constructor-inject the Func you registered //whenever this class is resolved. public NeedsAnElementFactory(Func elementFactory) { CreateElement = elementFactory; } public void MethodUsingElementFactory() { IHtml domInstance = GetTheDOM(); var element = CreateElement(domInstance); //the next line won't compile; //the factory method is strongly typed to IHtml var element2 = CreateElement("foo"); } } 

如果您想将代码保存在ElementFactory中而不是将其放在Autofac模块中,您可以将工厂方法设置为静态并注册(这在您的情况下特别有效,因为您的工厂方法通常是静态的):

 public class ElementFactory { public static IElement Create(IHtml dom) { switch (dom.ElementType) { case "table": return new TableElement(dom); case "div": return new DivElement(dom); case "span": return new SpanElement(dom); } return new PassthroughElement(dom); } } ... builder.Register>(ElementFactory.Create);