控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
#在ASP.NET下容器是怎样工作的 https://www.cnblogs.com/ms_senda/p/12516165.html 这篇随笔注释部分有简单介绍。
容器顾明思义就是一个装载物件的器皿,那么在软件里面就是装载各种对象和构建对象信息(参数)的一个器皿,这个器皿里面里面首先是存储的各种对象映射关系与构造参数信息
我们调用 Resolve<T> 获这得这个对象的具体实现与生命周期,容器总共有三种生命周期对象:
InstancePerLifetimeScope 同一个Lifetime生成的对象是同一个实例 (如应用域周期,一个http请求周期)
SingleInstance 单例模式,每次调用,都会使用同一个实例化的对象;每次都用同一个对象;
InstancePerDependency 默认模式,每次调用,都会重新实例化对象;每次请求都创建一个新的对象;
由于这个依赖注入框架其实还提供了很多复杂的参数与功能,我这里不以文字总结说明,后面以代码加注释方式记录autofac的主要应用。
// Create the builder with which components/services are registered. var builder = new ContainerBuilder(); // Register types that expose interfaces... builder.RegisterType<ConsoleLogger>().As<ILogger>(); // Register instances of objects you create... var output = new StringWriter(); builder.RegisterInstance(output).As<TextWriter>(); // Register expressions that execute to create objects... builder.Register(c => new ConfigReader("mysection")).As<IConfigReader>(); // Build the container to finalize registrations // and prepare for object resolution. var container = builder.Build(); // Now you can resolve services using Autofac. For example, // this line will execute the lambda expression registered // to the IConfigReader service. using(var scope = container.BeginLifetimeScope()) { var reader = scope.Resolve<IConfigReader>(); }
#依赖关系解析示例
public class MyComponent { public MyComponent() { /* ... */ } public MyComponent(ILogger logger) { /* ... */ } public MyComponent(ILogger logger, IConfigReader reader) { /* ... */ } } var builder = new ContainerBuilder(); builder.RegisterType<MyComponent>(); builder.RegisterType<ConsoleLogger>().As<ILogger>(); builder.RegisterType<MyComponent>() .UsingConstructor(typeof(ILogger), typeof(IConfigReader)); //强制使用第三个构造函数 builder.RegisterInstance(MySingleton.Instance).ExternallyOwned(); //当我们集成一个现有应用,并且这个应用公用的部分是一个静态类对象,
//我们为了达到新模块的依赖注入
//可以这样注入,但要加ExternallyOwned() 表示 //这个对象的内存管理是由自己管理,而不是交给容器管理。
var container = builder.Build(); using(var scope = container.BeginLifetimeScope()) { var component = scope.Resolve<MyComponent>(); //默认会调用第二个构造函数,发现IConfigReader 没有依赖信息 }
#表达式或者委托依赖关系注入
var builder = new ContainerBuilder(); builder.RegisterType<B>(); builder.Register(c => new C(Guid.NewGuid().ToString())).InstancePerLifetimeScope(); //但此处得这样注入才行,因为参数无法找到依赖 builder.RegisterType<A>().InstancePerLifetimeScope(); builder.Register(c => new A(c.Resolve<B>())).InstancePerLifetimeScope(); //此效果与上个一个注入效果相同 builder.Register(c => new A() { MyB = c.ResolveOptional<B>() }); //属性注入 var container = builder.Build(); A a1 = container.Resolve<A>(); A a2 = container.Resolve<A>();
#泛型组件注入
builder.RegisterGeneric(typeof(NHibernateRepository<>)) .As(typeof(IRepository<>)) .InstancePerLifetimeScope(); // Autofac will return an NHibernateRepository<Task> var tasks = container.Resolve<IRepository<Task>>();
#通过参数值选择具体的实现
builder.Register<CreditCard>( (c, p) => { var accountId = p.Named<string>("accountId"); if (accountId.StartsWith("9")) { return new GoldCard(accountId); } else { return new StandardCard(accountId); } }); var card = container.Resolve<CreditCard>(new NamedParameter("accountId", "12345"));
#默认注册
builder.RegisterType<ConsoleLogger>().As<ILogger>(); builder.RegisterType<FileLogger>().As<ILogger>().PreserveExistingDefaults(); //FileLogger 将不被注册,因为之前已ILogger被注册 builder.RegisterType<CallLogger>() .AsSelf() //注册自身为服务 .As<ILogger>() //注册为ILogger服务 .As<ICallInterceptor>(); //注册为ICallInterceptor服务 // These will all work because we exposed // the appropriate services in the registration: scope.Resolve<ILogger>(); scope.Resolve<ICallInterceptor>(); scope.Resolve<CallLogger>();
#有条件注册
var builder = new ContainerBuilder(); // Only ServiceA will be registered. // Note the IfNotRegistered takes the SERVICE TYPE to // check for (the As<T>), NOT the COMPONENT TYPE // (the RegisterType<T>). builder.RegisterType<ServiceA>() .As<IService>(); builder.RegisterType<ServiceB>() .As<IService>() .IfNotRegistered(typeof(IService)); // HandlerA WILL be registered - it's running // BEFORE HandlerB has a chance to be registered // so the IfNotRegistered check won't find it. // // HandlerC will NOT be registered because it // runs AFTER HandlerB. Note it can check for // the type "HandlerB" because HandlerB registered // AsSelf() not just As<IHandler>(). Again, // IfNotRegistered can only check for "As" // types. builder.RegisterType<HandlerA>() .AsSelf() .As<IHandler>() .IfNotRegistered(typeof(HandlerB)); builder.RegisterType<HandlerB>() .AsSelf() .As<IHandler>(); builder.RegisterType<HandlerC>() .AsSelf() .As<IHandler>() .IfNotRegistered(typeof(HandlerB)); // Manager will be registered because both an IService // and HandlerB are registered. The OnlyIf predicate // can allow a lot more flexibility. builder.RegisterType<Manager>() .As<IManager>() .OnlyIf(reg => reg.IsRegistered(new TypedService(typeof(IService))) && reg.IsRegistered(new TypedService(typeof(HandlerB)))); // This is when the conditionals actually run. Again, // they run in the order the registrations were added // to the ContainerBuilder. var container = builder.Build();
#属性和方法注入
属性注入
var builder = new ContainerBuilder(); builder.RegisterType<AB>(); builder.Register<AC>(c => new AC { B = c.Resolve<AB>() }); builder.RegisterType<AC>().PropertiesAutowired(); builder.Register(c => new AC()).OnActivated(e => e.Instance.B = e.Context.Resolve<AB>()); builder.RegisterType<AC>().WithProperty("B", new AB()); var container = builder.Build(); using (var scope = container.BeginLifetimeScope()) { AC aC = scope.Resolve<AC>(); Console.WriteLine(aC.Name); Console.WriteLine(aC.B.Name); }
#方法注入
builder.Register(c => { var result = new AC(); var dep = c.Resolve<AB>(); result.SetTheDependency(dep); return result; }).InstancePerLifetimeScope(); //指明类型构建规则和属性依赖注入 //这里相当于显示创建,但最终生命周期交 //容器管理