简体   繁体   English

用 AutoFac 替换工厂

[英]Replace factory with AutoFac

I'm accustomed to creating my own factories as shown (this is simplified for illustration):我习惯于创建自己的工厂,如图所示(为了说明,这是简化的):

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

I'm finally getting around to using an IoC container (AutoFac) in my current project, and I'm wondering is there some magic way of achieving the same thing elegantly with AutoFac?我终于开始在我当前的项目中使用 IoC 容器 (AutoFac),我想知道是否有一些神奇的方法可以用 AutoFac 优雅地实现同样的事情?

Short answer: Yes.简短的回答:是的。

Longer answer: First, in simple cases where a class Foo is registered as the implementation for IFoo, constructor parameters or properties of type Func<IFoo> will be resolved automatically by Autofac, with no additional wiring needed.更长的答案:首先,在类 Foo 注册为 IFoo 的实现的简单情况下,构造函数参数或Func<IFoo>类型的属性将由 Autofac 自动解析,无需额外的接线。 Autofac will inject a delegate that basically executes container.Resolve<IFoo>() when invoked. Autofac 将注入一个委托,该委托在调用时基本上执行container.Resolve<IFoo>()

In more complex cases like yours, where the exact concretion returned is based on input parameters, you can do one of two things.在像您这样的更复杂的情况下,返回的确切混凝土基于输入参数,您可以执行以下两项操作之一。 First, you can register a factory method as its return value to provide a parameterized resolution:首先,您可以注册一个工厂方法作为其返回值以提供参数化的解析:

builder.Register<IElement>((c, p) => {
    var dom= p.Named<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);
  });

//usage
container.Resolve<IElement>(new NamedParameter("dom", domInstance))

This isn't type-safe (domInstance won't be compiler-checked to ensure it's an IHtml), nor very clean.这不是类型安全的(domInstance 不会被编译器检查以确保它是 IHtml),也不是很干净。 Instead, another solution is to actually register the factory method as a Func:相反,另一种解决方案是将工厂方法实际注册为 Func:

builder.Register<Func<IHtml, IElement>>(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<IHtml,IElement> CreateElement {get; private set;}

    //AutoFac will constructor-inject the Func you registered
    //whenever this class is resolved.
    public NeedsAnElementFactory(Func<IHtml,IElement> 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");
    }
}

If you wanted to keep the code in ElementFactory instead of putting it in the Autofac module, you could make the factory method static and register that (this works especially well in your case because your factory method is trivially made static):如果您想将代码保留在 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<Func<IHtml, IElement>>(ElementFactory.Create);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM