Ответ 1
Короткий ответ: Да.
Более длинный ответ: во-первых, в простых случаях, когда класс Foo зарегистрирован как реализация для IFoo, параметры конструктора или свойства типа Func<IFoo>
будут автоматически разрешаться Autofac без дополнительной проводки. Autofac будет вводить делегат, который в основном выполняет container.Resolve<IFoo>()
при вызове.
В более сложных случаях, подобных вашим, где точное конкретирование возвращается на основе входных параметров, вы можете сделать одну из двух вещей. Во-первых, вы можете зарегистрировать метод factory в качестве возвращаемого значения для обеспечения параметризованного разрешения:
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))
Это не безопасно для типов (domInstance не будет проверяться компилятором, чтобы гарантировать его IHtml), и не очень чистый. Вместо этого другим решением является фактически зарегистрировать метод factory как 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");
}
}
Если вы хотите сохранить код в ElementFactory вместо того, чтобы поместить его в модуль Autofac, вы можете сделать статический метод factory и зарегистрировать его (это особенно хорошо работает в вашем случае, потому что ваш метод factory тривиально выполнен статический):
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);