最近在研究Nopcommerce,发现其内部IOC框架使用了autofac,简单的了解了一下,记录一下简单的一些用法。初浅了解下来,有一个很直观的感受,就是对代码几乎没什么侵入性,其他性能之类没有测试,但据说性能极佳。
1. 构造函数注入,如下示例(后面所有说明都是在以下的示例基础上进行的)
public interface IRepository
{
void Update();
}
public class FirstRepository : IRepository
{
public void Update()
{
Console.WriteLine("FirstRepository.Update");
}
}
public class SecondRepository : IRepository
{
public void Update()
{
Console.WriteLine("SecondRepository.Update");
}
}
public class ConcreteController
{
private IRepository _repository;
public ConcreteController(IRepository repository)
{
_repository = repository;
}
public void Update()
{
_repository.Update();
}
}
调用如下:
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<ConcreteController>().AsSelf();//也可直接写成builder.RegisterType<ConcreteController>()
builder.RegisterType<FirstRepository>().As<IRepository>();//注册FirstRepository为IRespository默认实现
IContainer container = builder.Build();
//默认以类参数最多的构造方法进行构造,构造参数根据类型从注册列表中寻找注册的实现类,此处获取的是FirstRepository
ConcreteController controller = container.Resolve<ConcreteController>();
controller.Update();//FirstRepository.Update
对同一接口多次注册时,会以最后一次注册的实现类为默认实现类,如下:
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<ConcreteController>().AsSelf();//也可直接写成builder.RegisterType<ConcreteController>()
builder.RegisterType<FirstRepository>().As<IRepository>();
builder.RegisterType<SecondRepository>().As<IRepository>();//IRepository的默认实现类为SecondRepository
IContainer container = builder.Build();
ConcreteController controller = container.Resolve<ConcreteController>();
controller.Update();//SecondRepository.Update
如果有这样的一个需求:如果前面注册过了接口的实现类,则以之前注册过的实现类为默认值,如果没有注册过则以此次注册的实现类为默认值,可以通过以下方式实现:
//如果之前存在默认值则以之前注册的值为默认值,否则以此次注册的实现类为默认值
builder.RegisterType<SecondRepository>().As<IRepository>().PreserveExistingDefaults();
...
controller.Update();//FirstRepository.Update
在注册时,可以通过委托的方式,预先指定一个接口的实现类。即采用ContainerBuilder.Register<T>(委托)的方式来进行实现,如下:
ContainerBuilder builder = new ContainerBuilder();
//通过Register方法,预先指定一个获取实现的委托来注册接口的实现类
builder.Register<IRepository>(r => new FirstRepository());
IContainer container = builder.Build();
IRepository repository = container.Resolve<IRepository>();//FirstRepository
repository.Update();//FirstRepository.Update
autofac构造注入时,在通过无参的IContainer.resolver获取实现类时,会默认通过实现类最多的参数进行构造,构造方法的参数值为该参数类型注册的实现类。如果该参数值的Type没有在autofac进行注册,则直接报错,如下:
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<ConcreteController>();
IContainer container = builder.Build();
//ConcreteController的构造方法中需要一个IRepository参数,但autofac检索不到IRepository的实现类,注入失败,报错
//此处不光是针对参数值是引用类型,对于值类型同样存在这样的问题,例如把参数换成int i,同样注入失败,报错
ConcreteController controller = container.Resolve<ConcreteController>();//error
对于这样的问题,可以通过在Resolve
时,自行装配,如下:
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<ConcreteController>();
IContainer container = builder.Build();
//之前没有对ConcreteController构造方法中的参数repository类型IRepository进行注册,但可在解析提取时自动注入