问题
I think I get most things about dependency inversion and using an IoC container, but one thing still does not appear clear to me. How do I use autofac to automate the following factory:
public class WidgetFactory
{
public static IWidget Create(int foo, double bar)
{
return new Widget(foo, bar);
}
}
public class Widget
{
private readonly int foo;
private readonly double bar;
public Widget(int foo, double bar)
{
this.foo = foo;
this.bar = bar;
}
}
elsewhere...
public class FoobarUser
{
public void Method()
{
var widget = WidgetFactory.Create(3, 4.863);
// Do something with my widget
// Possibly add it to a widget collection
}
}
Basically, I need thousands of widgets to be created and I'm not sure of the best way of doing so. How would I create the widget factory using autofac and how would I use that in Method, bearing in mind that Method does not contain a reference to the IContainer?
回答1:
The way to fix this problem is the following:
Change WidgetFactory to define a delegate for creating widgets:
public class WidgetFactory
{
public delegate IWidget Create(int firstParam, double secondParam);
}
In your autofac module, wire up the factory using the RegisterGeneratedFactory method. This will automatically create your factory for you:
public class TestClassModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterType<Widget>().As<IWidget>();
builder.RegisterGeneratedFactory<WidgetFactory.Create>(new TypedService(typeof(IWidget)));
builder.RegisterType<FoobarUser>();
}
}
Inject the factory into FoobarUser:
public class FoobarUser
{
private readonly WidgetFactory.Create factory;
public FoobarUser(WidgetFactory.Create factory)
{
this.factory = factory;
}
public void Method()
{
var widget = this.factory(3, 4.836);
// Do something with my widget
// Possibly add it to a widget collection
}
}
回答2:
There are basically two ways to handle parameters:
- At registration time - you can provide them in lambda registrations (
Register(c => T)
) or you can append parameters to reflection-based (RegisterType<T>
) registrations. - At resolve time - you can either append parameters to
Resolve<T>()
calls or you can use delegate factories orFunc<T>
dependencies to dynamically create a factory method that can be used by your component.
There is robust documentation on all of these options with examples over at the Autofac documentation site:
- Parameters at registration time
- Parameters at resolve time
回答3:
You would inject dependencies into your factory with an IoC container using constructor or property injection, not args into a method. If you needed to inject specific values as parameters into your service's constructor, you could set that up during registration similar to the below code.
Here, I'm getting a XML file path from my web.config and passing that value into my repository's constructor:
var builder = new ContainerBuilder();
var xmlFileName = HttpContext.Current.Server.MapPath(
ConfigurationManager.AppSettings["xmlData"]);
builder.Register(c => new XmlAdvertisementRepository(new XmlContext(xmlFileName)))
.AsImplementedInterfaces()
.InstancePerHttpRequest();
来源:https://stackoverflow.com/questions/24876393/what-is-the-proper-way-to-create-objects-which-require-parameters-using-autofac