我对autofac很新,所以我可能会完全滥用它。
假设我有一个具有这种结构的类:
public class HelperClass : IHelperClass
{
public HelperClass(string a, string b)
{
this.A = a;
this.B = b;
}
}
我有两个使用该类的类,但构造函数需要不同的默认值。第二个构造函数仅用于测试目的 - 我们总是希望在“真实”应用程序中使用HelperClass。:
public class DoesSomething: IDoesSomething
{
public DoesSomething()
: this(new HelperClass("do", "something"));
{
}
internal DoesSomething(IHelperClass helper)
{
this.Helper = helper;
}
}
public class DoesSomethingElse : IDoesSomethingElse
{
public DoesSomethingElse()
: this(new HelperClass("does", "somethingelse"));
{
}
internal DoesSomethingElse(IHelperClass helper)
{
this.Helper = helper;
}
}
这是我的AutoFac模块:
public class SomethingModule: Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<DoesSomething>().As<IDoesSomething>();
builder.RegisterType<DoesSomethingElse>().As<IDoesSomethingElse();
}
}
我的问题:
答案 0 :(得分:51)
您始终可以使用WithParameter
方法显式指定构造函数参数:
builder.RegisterType<DoesSomething>()
.As<IDoesSomething>()
.WithParameter("helper", new HelperClass("do", "something"));
builder.RegisterType<DoesSomethingElse>()
.As<IDoesSomethingElse>()
.WithParameter("helper", new HelperClass("do", "somethingelse"));
据我所知,HelperClass
不需要接口,因为它基本上只是一个价值持有者。
为此,你需要公开内部构造函数。
答案 1 :(得分:41)
有两种方法可以在Autofac中传递参数:
<强> When you are registering the component 强>
注册组件时,您可以提供一组参数,这些参数可以在基于该组件的服务解析期间使用。 Autofac提供了几种不同的参数匹配策略:
NamedParameter
- 按名称匹配目标参数TypedParameter
- 按类型匹配目标参数(确切类型匹配
需要) ResolvedParameter
- 灵活的参数匹配
// Using a NAMED parameter:
builder.RegisterType<ConfigReader>()
.As<IConfigReader>()
.WithParameter("configSectionName", "sectionName");// parameter name, parameter value. It's the same of this: new NamedParameter("configSectionName", "sectionName")
// Using a TYPED parameter:
builder.RegisterType<ConfigReader>()
.As<IConfigReader>()
.WithParameter(new TypedParameter(typeof(string), "sectionName"));
// Using a RESOLVED parameter:
builder.RegisterType<ConfigReader>()
.As<IConfigReader>()
.WithParameter(
new ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(string) && pi.Name == "configSectionName",
(pi, ctx) => "sectionName"));
NamedParameter
和TypedParameter
只能提供常量值。
ResolvedParameter
可用作提供从容器动态检索的值的方法,例如通过名称解析服务。
如果您想要将已注册的服务(例如IConfiguration
)作为参数传递,您可以解析参数,如下所示:
builder.RegisterType<Service>()
.As<Iervice>()
.WithParameter((pi, ctx) => pi.ParameterType == typeof(IConfiguration) && pi.Name == "configuration",
(pi, ctx) => ctx.Resolve<IConfiguration>());
<强> When you are resolving the component 强>
在Autofac中在运行时传递参数的一种方法是使用Resolve
方法。你可以创建一个这样的类:
public class ContainerManager
{
public IContainer Container {get;set;}
//...
public T[] ResolveAllWithParameters<T>(IEnumerable<Parameter> parameters)
{
return Container.Resolve<IEnumerable<T>>(parameters).ToArray();
}
}
Parameter
是一个属于Autofac的抽象类,您可以使用NamedParameter
类来传递所需的参数。您可以使用我在下面显示的ContainerManager
课程:
public T[] ResolveAllWithParameters<T>(IDictionary<string,object> parameters )
{
var _parameters=new List<Parameter>();
foreach (var parameter in parameters)
{
_parameters.Add( new NamedParameter(parameter.Key, parameter.Value));
}
return ContainerManager.ResolveAllWithParameters<T>(_parameters);
}
这样,您可以在解析特定组件时使用Dictionary<string, object>
在运行时传递参数。
使用Extension Method可能更简单:
public static class ContainerExtensions
{
public static T[] ResolveAllWithParameters<T>(this IContainer Container, IDictionary<string, object> parameters)
{
var _parameters = new List<Parameter>();
foreach (var parameter in parameters)
{
_parameters.Add(new NamedParameter(parameter.Key, parameter.Value));
}
return Container.Resolve<IEnumerable<T>>(_parameters).ToArray();
}
}
答案 2 :(得分:10)
Autofac不使用非公共构造函数。默认情况下,它只查找公共的,而不会看到其他的。除非您使用.FindConstructorsWith(BindingFlags.NonPublic)
,否则它只会看到公共构造函数。因此,您的方案应该按照您的预期进行。
答案 3 :(得分:2)
是的,只能传递一组子参数:
public Contract(IPerson person, String name)
{
this.Person = person;
person.Name = name;
}
....
// this uses the person/name ctor. Person is factored and injected by the contianer
List<Parameter> parameters = new List<Parameter>();
parameters.Add(new NamedParameter("name", "cloe"));
contract = scope.Resolve<IContract>(parameters);