阅读目录
2、常用框架——.NET Core内置IOC容器ServiceCollection
3、IOC框架——Autofac框架【后面专门拿一节来总结】
要说依赖注入DI首先要从控制反转IOC说起,为什么这么讲呢?因为控制反转是思想,依赖注入是当下的最佳实践。传统的程序设计,我们直接在对象内部去new出依赖的对象,而IOC思想中,使用一个专门的容器来创建管理这些对象及其依赖的对象的生命周期《如图1》。传统程序设计都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松耦合方便测试,利于功能复用,使整个程序变得非常灵活。其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。
2、常用框架——.NET Core内置IOC容器ServiceCollection
ServiceCollection是.NET Core内置的DI框架,使用的时候需要引入 Microsoft.Extensions.DependencyInjection 6.0.0 Nuget包。此包提供了 IServiceCollection 接口的入口,从而公开你可以从中调用 GetService<TService> 的 System.IServiceProvider。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 namespace Demo07_ServiceCollection 2 { 3 public interface ISqlHelper 4 { 5 void GetInfo(); 6 } 7 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Demo07_ServiceCollection 8 { 9 public class SqlServerHelper : ISqlHelper 10 { 11 public void GetInfo() 12 { 13 Console.WriteLine("这个是SqlServer"); 14 } 15 } 16 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Demo07_ServiceCollection 8 { 9 public class MySqlHelper : ISqlHelper 10 { 11 public void GetInfo() 12 { 13 Console.WriteLine("这个是MySql"); 14 } 15 } 16 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using Microsoft.Extensions.DependencyInjection; 2 using System; 3 4 namespace Demo07_ServiceCollection 5 { 6 internal class Program 7 { 8 static void Main(string[] args) 9 { 10 //1、创建依赖注入服务 11 ServiceCollection services = new ServiceCollection(); 12 //2、配置服务容器《添加组件生命周期和实例化对象》 13 services.AddTransient<ISqlHelper, SqlServerHelper>(); //services.AddTransient<ISqlHelper, MySqlHelper>(); 14 //3、构建服务容器 15 var provider = services.BuildServiceProvider(); 16 //4、用服务容器创建服务实例 17 var sqlHelper = provider.GetService<ISqlHelper>(); 18 //5、使用服务实例 19 sqlHelper.GetInfo(); 20 Console.ReadKey(); 21 } 22 } 23 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 namespace Demo07_ServiceCollection 2 { 3 public interface ILogger 4 { 5 void Log(string msg); 6 } 7 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Demo07_ServiceCollection 8 { 9 public class Logger : ILogger 10 { 11 public void Log(string msg) 12 { 13 Console.WriteLine($"Logger:{msg}"); 14 } 15 } 16 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 namespace Demo07_ServiceCollection 2 { 3 public interface ISqlHelper 4 { 5 void GetInfo(); 6 } 7 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 namespace Demo07_ServiceCollection 2 { 3 public class SqlServerHelper : ISqlHelper 4 { 5 private ILogger _logger; 6 public SqlServerHelper(ILogger logger) 7 { 8 _logger=logger; 9 } 10 public void GetInfo() 11 { 12 _logger.Log("这个是SqlServer"); 13 } 14 } 15 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 namespace Demo07_ServiceCollection 2 { 3 public class MySqlHelper : ISqlHelper 4 { 5 private ILogger _logger; 6 public MySqlHelper(ILogger logger) 7 { 8 _logger = logger; 9 } 10 public void GetInfo() 11 { 12 _logger.Log("这个是MySql"); 13 } 14 } 15 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using Microsoft.Extensions.DependencyInjection; 2 using System; 3 4 namespace Demo07_ServiceCollection 5 { 6 internal class Program 7 { 8 static void Main(string[] args) 9 { 10 //1、创建依赖注入服务 11 ServiceCollection services = new ServiceCollection(); 12 //2、配置服务容器《添加组件生命周期和实例化对象》 13 services.AddTransient<ISqlHelper, SqlServerHelper>(); //services.AddTransient<ISqlHelper, MySqlHelper>(); 14 services.AddTransient<ILogger,Logger>(); 15 //3、构建服务容器 16 var provider = services.BuildServiceProvider(); 17 //4、用服务容器创建服务实例 18 var sqlHelper = provider.GetService<ISqlHelper>(); 19 //5、使用服务实例 20 sqlHelper.GetInfo(); 21 Console.ReadKey(); 22 } 23 } 24 }
从上面的例子可以看出,在配置服务容器的时候,可以使用 services.AddTransient<ILogger,Logger>(); services.AddScoped<ILogger, Logger>(); services.AddSingleton<ILogger, Logger>(); 来添加添加组件生命周期和实例化对象,尖括号里面配置注入的接口和实例化使用对象,①AddTransient:瞬时,每次的实例都是一个新的对象;②AddScoped:作用域,在一个作用域中唯一实例,比如在Asp.Net Core应用程序中一次请求相当于一个Scoped;③AddSingleton:单例,全局唯一实例。
3、IOC框架——Autofac框架【后面专门拿一节来总结】
Unity是微软patterns& practices组用C#实现的轻量级、可扩展的依赖注入容器,官方网站是:http://unity.codeplex.com/,我们可以通过代码或者XML配置文件的形式来配置对象与对象之间的关系,在运行时直接调用Unity容器即可获取我们所需的对象,以便建立松散耦合的应用程序。使用的时候需要NuGet引入 Unity 5.11.10 。依赖注入划分为3 种形式,即构造器注入、属性(设置)注入和方法参数注入。对于小型项目:用代码的方式实现即可;对于中大型项目:使用配置文件比较好。
Unity可以使用编程方式注入也可以通过配置文件的方式实现注入,编程注入步骤是:①创建一个UnityContainer对象。②通过Unity Container对象的RegisterType方法把依赖对象关联进来。③通过UnityContainer对象的Resolve方法来创建获取指定对象。下面 3.2 - 3.4 小结就来介绍这种编程注入的方式。
Unity容器创建对象的时候,需要依赖另外一个对象,通过构造函数传入依赖对象接口的方式来注入创建。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 namespace Demo07_Unity 2 { 3 public interface IWater 4 { 5 string GetWaterName(); 6 } 7 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 namespace Demo07_Unity 2 { 3 public class Wahaha : IWater 4 { 5 public string GetWaterName() 6 { 7 return "哇哈哈矿泉水"; 8 } 9 } 10 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 namespace Demo07_Unity 2 { 3 public interface IPeople 4 { 5 /// <summary> 6 /// 喝水 7 /// </summary> 8 void DrinkWater(); 9 } 10 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
namespace Demo07_Unity { /// <summary> /// 战士 /// </summary> public class Warrior : IPeople { private readonly IWater _water; public Warrior(IWater water) { this._water = water; } public void DrinkWater() { Console.WriteLine($"【{_water.GetWaterName()}】 真好喝,甘甜解渴!"); } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Unity; 7 8 namespace Demo07_Unity 9 { 10 public class CtorMain 11 { 12 public static void Test() 13 { 14 //1、创建IOC容器 15 UnityContainer unityContainer = new UnityContainer(); 16 //2、注册依赖对象 17 unityContainer.RegisterType<IWater, Wahaha>(); 18 //unityContainer.RegisterType<IWater, Wahaha>(TypeLifetime.Singleton); //添加生命周期 19 //3、创建对象 20 IPeople warrior = unityContainer.Resolve<Warrior>(); 21 //4、执行对象方法 22 warrior.DrinkWater(); 23 } 24 } 25 }
属性注入只需要在属性字段上用特性 [Dependency] 标记就行了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 namespace Demo07_Unity 2 { 3 public interface IProduct 4 { 5 void ShowName(); 6 } 7 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Demo07_Unity 8 { 9 public class Milk : IProduct 10 { 11 12 public void ShowName() 13 { 14 Console.WriteLine("蒙牛牛奶"); 15 } 16 } 17 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using Unity; 2 3 namespace Demo07_Unity 4 { 5 public class ShoppingCart 6 { 7 [Dependency] 8 public IProduct Product { get; set; } 9 public void Show() 10 { 11 Product.ShowName(); 12 } 13 } 14 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Unity; 7 8 namespace Demo07_Unity 9 { 10 public class PropMain 11 { 12 public static void Test() 13 { 14 //1、创建IOC容器 15 UnityContainer unityContainer = new UnityContainer(); 16 //2、注册依赖对象 17 unityContainer.RegisterType<IProduct, Milk>(); 18 //3、创建对象 19 ShoppingCart shoppingCart = unityContainer.Resolve<ShoppingCart>(); 20 //ShoppingCart shoppingCart = unityContainer.Resolve<ShoppingCart>(TypeLifetime.Singleton); //添加生命周期 21 //4、执行对象方法 22 shoppingCart.Show(); 23 } 24 } 25 }
方法参数注入和属性方式使用一样,方法参数注入只需要在方法上使用特性 [InjectionMethod] 标记就行了,注意:只有方法参数需要依赖对象的时候注入才有效。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 namespace Demo07_Unity 2 { 3 public interface IFood 4 { 5 string GetName(); 6 } 7 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 namespace Demo07_Unity 2 { 3 public class Fish : IFood 4 { 5 public string GetName() 6 { 7 return "大青鱼"; 8 } 9 } 10 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using Unity; 2 3 namespace Demo07_Unity 4 { 5 public class Cat 6 { 7 public IFood food1;//用这个字段来观察下面方法注入的参数是否有效 8 9 [InjectionMethod] 10 public void Eat(IFood food) 11 { 12 food1=food; 13 } 14 15 } 16 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Unity; 7 8 namespace Demo07_Unity 9 { 10 public class MethodMain 11 { 12 public static void Test() 13 { 14 //1、创建IOC容器 15 UnityContainer unityContainer = new UnityContainer(); 16 //2、注册依赖对象 17 unityContainer.RegisterType<IFood, Fish>(); 18 //unityContainer.RegisterType<IFood, Fish>(TypeLifetime.Singleton); //添加生命周期 19 //3、创建对象 20 Cat cat = unityContainer.Resolve<Cat>(); 21 //4、调用cat实例方法 22 Console.WriteLine(cat.food1.GetName()); 23 24 } 25 } 26 }
上面介绍的三种注入方式,包括依赖对象生命周期管理都在代码中实现,这种代码实现会产生耦合度,比如添加一个属性注入或是方法参数注入都要去属性或是方法前加特性 [Dependency] 、 [InjectionMethod] 来标记,理想的依赖注入应该是在配置文件中配置,系统发生变化不影响代码,改配置文件就能达到效果。需要注意配置节点需要Nuget应用程序集 Unity.Configuration 才能识别配置文件中的 unity 配置段, Unity容器使用配置文件来注入的时候,需要另外Nuget导入 Unity.Configuration 5.11.2 包和 Unity.Interception.Configuration 5.11.1 包和 Unity.Abstractions 5.11.7 包,这用来识别配置文件里依赖注入配置。
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <!--设置配置节点信息,注明UnityConfigurationSection类所在程序集和完整类名--> 4 <configSections> 5 <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/> 6 </configSections> 7 <!--容器配置节点--> 8 <unity> 9 <!--加载模式扩展,InterceptionConfigurationExtension--> 10 <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/> 11 <!--默认容器--> 12 <container name="MyContainer"> 13 <!--向 Unity 容器添加容器扩展--> 14 <extension type="Interception"/> 15 <!--类型的注册信息,注意:完整类名,程序集名--> 16 <register type="Demo07_Unity.IGoods,Demo07-Unity" mapTo="Demo07_Unity.Apple,Demo07-Unity"> 17 <!--创建生命周期配置,默认是瞬时Transient,单例Singleton--> 18 <lifetime type="singleton"></lifetime> 19 <!--构造函数注入配置--> 20 <constructor></constructor> 21 <!--属性字段注入配置--> 22 <property></property> 23 <!--方法参数注入配置--> 24 <method></method> 25 </register> 26 <!--直接在容器中创建实例--> 27 <instance></instance> 28 </container> 29 <!--otherContainer容器--> 30 <container name="otherContainer"> 31 32 </container> 33 34 </unity> 35 </configuration>
<unity> 配置部分
Element |
Number |
Description |
---|---|---|
<alias> |
Many |
创建类型别名。该元素是可选的。 |
<namespace> |
Many |
将命名空间添加到命名空间搜索列表。该元素是可选的。 |
<assembly> |
Many |
将程序集添加到程序集搜索列表中。该元素是可选的。 |
<sectionExtension> |
Many |
添加部分扩展,将新支持的元素添加到配置架构。该元素是可选的。 |
<container> |
Many |
一组容器配置。该元素是可选的。 |
<container> 配置部分
包含一组用于统一容器实例配置。下表列出了<container>元素的属性。
属性 |
描述 |
---|---|
name |
此容器配置的名称。节中的一个容器元素可以省略 name 属性;所有其他人必须有唯一的名字。未命名的 <container> 元素被视为默认元素,如果在调用 container.LoadConfiguration 时省略容器名称,则会加载该元素。该属性是可选的。有关更多信息,请参阅加载配置文件信息。 |
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <unity xmlns="https://schemas.microsoft.com/practices/2010/unity"> 2 <container> <!-- default container --> 3 … content here ... 4 </container> 5 <container name="otherContainer"> 6 ... content here ... 7 </container> 8 </unity>
元素 |
数字 |
描述 |
---|---|---|
<register> |
Many |
类型的注册信息。该元素是可选的。 |
<instance> |
Many |
直接在容器中创建实例。该元素是可选的。 |
<extension> |
Many |
向 Unity 容器添加容器扩展。该元素是可选的。 |
<register> 配置部分
< register>元素是任何配置文件的基本构建块。它使您能够为类型指定类型映射和注入配置。如果您指定一个名称,该名称将用于类型映射。如果不指定名称,则会为指定类型创建默认映射。您可以为每个映射指定一个生命周期管理器。如果没有为类型配置显式生命周期管理器,它将使用瞬态生命周期管理器。下表列出了 < register>元素的属性。
属性 |
描述 |
---|---|
type |
正在注册的类型。这是调用Resolve方法时将请求的类型。此属性是必需的。 |
name |
注册名称;如果省略,将创建该类型的默认注册。该属性是可选的。 |
mapTo |
调用Resolve时实际创建和返回的类型。这将设置类型映射。它可以是用户定义的别名或默认别名之一。该属性是可选的。 |
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <container> 2 <register type="MyService"> ... </register> <!-- Default registration for type MyService --> 3 <register type="ILogger" mapTo="EventLogLogger" /> <!-- type mapping --> 4 <register type="ILogger" mapTo="PageAdminLogger" name="emergency" /> <!-- named registration --> 5 </container>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //注册具有临时生存期的默认(未命名)类型映射指定注册的类型作为接口或对象类型,以及要为该类型返回的目标类型 2 myContainer.RegisterType<ILogger, EventLogLogger>();
下表列出了<register>元素的子元素。使用拦截配置扩展Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension 时,附加元素是<register>元素的有效子元素。有关更多信息,请参阅拦截配置架构元素。
元素 |
数字 |
描述 |
---|---|---|
<lifetime> |
One |
管理容器创建的实例的类型。该元素是可选的。 |
<constructor> |
One |
配置要在创建实例时调用的构造函数。该元素是可选的。 |
<property> |
许多 |
配置将在创建实例时设置的属性。该元素是可选的。 |
<method> |
许多 |
配置将在创建实例时调用的方法。该元素是可选的。 |
<constructor> 元素
此类型的构造函数的 **<constructor>** 元素配置并包含此对象类型的构造函数注入要求的详细信息。该构造元素没有属性。每个寄存器部分只能包含一个<constructor>元素。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <register type="ILogger" mapTo="SerialPortLogger"> 2 <!-- Call the constructor with one parameter named "port" --> 3 <constructor> 4 <param name="port" value="COM1:" /> 5 </constructor> 6 </register>
元素 |
数字 |
描述 |
---|---|---|
<param> |
Many |
指定要调用的构造函数的参数。如果不存在<param>子元素,则表示应调用零参数构造函数。该元素是可选的。 |
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 container.RegisterType<ILogger, TraceSourceLogger>( 2 "UI", 3 new InjectionConstructor("UI")); 4 container.RegisterType<DriveController>( 5 new InjectionProperty("MyProperty")); 6 container.RegisterType<DriveController>( 7 new InjectionMethod("InitializeMe", 42.0, 8 new ResolvedParameter(typeof(ILogger), "SpecialLogger")));
<property> 元素
**<property>** 元素为注入配置一个属性。它包含此对象类型的属性注入要求的详细信息。您可以在每个<register>元素中包含一个或多个 **<property>** 元素。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <register type="ILogger" mapTo="SerialPortLogger"> 2 <!-- Inject the property "Settings" --> 3 <property name="Settings" /> 4 </register>
属性 |
描述 |
---|---|
name |
属性的名称。此属性是必需的。 |
dependencyName |
如果存在,请使用此名称而不是默认值解析属性的值。该属性是可选的。 |
dependencyType |
如果存在,则指示要解析的属性值的类型。如果未给出,则属性的类型是已解析的类型。该属性是可选的。 |
value |
要存储在属性中的值。使用该类型的默认 TypeConverter 将此字符串转换为该属性的类型。该属性是可选的。 |
元素 |
数字 |
描述 |
---|---|---|
<dependency> |
One |
指定如何解析要存储在属性中的值。该元素是可选的。 |
<value> |
One |
指定要存储在属性中的文字值。该元素是可选的。 |
<optional> |
One |
指定应为属性解析可选值。该元素是可选的。 |
<array> |
One |
为数组类型的属性配置数组值的注入。该元素是可选的。 |
<method> 元素
所述<method>元素配置一个将被称为创建一个实例的一部分的方法。它包含此对象类型的方法注入要求的详细信息。您可以为每个 < register>元素包含一个或多个<method>元素。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <register type="MyLogger"> 2 <method name="Initialize"> 3 <param name="loggerSettings" /> 4 </method> 5 </register>
属性 |
描述 |
---|---|
name |
要调用的方法的名称。此属性是必需的。 |
元素 |
数字 |
描述 |
---|---|---|
<param> |
Many |
指定要调用的方法的参数。如果不存在<param>子元素,则表示该方法没有参数。此元素是可选的。 |
<param> 元素
所述<PARAM>元素指定构造方法或方法喷射的参数。它用于根据构造函数或方法的参数的名称(和可选的类型)确定调用哪个构造函数或方法重载。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <constructor> 2 <param name="param1" /> 3 <param name="param2" value="Hello World!" /> 4 </constructor>
属性 |
描述 |
---|---|
name |
参数的名称。此属性是必需的。 |
type |
参数的类型。仅当存在具有相同参数名称的两个不同重载并且您需要根据类型区分它们时,才需要此属性。通常,仅参数名称就足够了。该属性是可选的。 |
dependencyName |
用于解析依赖项的名称。该属性是可选的。 |
dependencyType |
要解决的依赖项类型。该属性是可选的。 |
value |
要为此参数注入的值。该属性是可选的。 |
元素 |
数字 |
描述 |
---|---|---|
<dependency> |
One |
通过容器解析参数的值。该元素是可选的。 |
<optional> |
One |
通过容器解析可选值。该元素是可选的。 |
<value> |
One |
给出用于参数值的显式值。该元素是可选的。 |
<array> |
One |
如果参数是数组类型,则指定要放入解析数组的值。该元素是可选的。 |
<dependency> 元素
所述<dependency>元件时使用的值是通过容器来解决。默认情况下,在没有其他配置的情况下,此元素会导致回调到容器中,以获取包含参数或属性类型的默认值。属性可用于自定义解析的内容。如果无法解析该值,则在解析时抛出异常。以下示例显示了<dependency>元素的常见用法。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <constructor> 2 <param name="param1"> 3 <dependency name="otherRegistration" /> 4 </param> 5 </constructor>
属性 |
描述 |
---|---|
name |
在容器中注册的命名类型或映射的名称,用于解析此依赖项。如果省略,将解析默认注册。该属性是可选的。 |
type |
键入以从容器解析。它必须是与参数或属性的类型兼容的类型。如果省略,Unity 根据父参数或属性的类型解析类型。该属性是可选的。 |
<value> 元素
所述<value>元素用于指定一个参数或属性的特定值。此元素允许您指定一个字符串,然后通过TypeConverter传递该字符串以创建要注入的实际对象。如果没有给出特定的类型转换器类型,则使用参数或属性类型的默认类型转换器。
使用不变区域性将字符串转换为对象;如果您希望使用特定于语言环境的文化,则必须提供自定义TypeConverter才能这样做。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <constructor> 2 <param name="param1"> 3 <value value="42" /> 4 </param> 5 <param name="param2"> 6 <value value="aieou" typeConverter="VowelTypeConverter" /> 7 </param> 8 </constructor>
属性 |
描述 |
---|---|
value |
要转换为对象的字符串值。此属性是必需的。 |
typeConverter |
用于将值转换为对象的TypeConverter 的类型。如果省略,将使用包含参数或属性类型的默认类型转换器。该属性是可选的。 |
<optional> 元素
所述<可选>元件时使用的值应通过容器来解决,但其存在是任选的。容器将尝试使用容器中注册的类型和映射来解析此参数或属性,但如果解析失败,容器将返回null而不是抛出异常。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <constructor> 2 <param name="param1"> 3 <optional name="otherRegistration" /> 4 </param> 5 </constructor>
属性 |
描述 |
---|---|
name |
在容器中注册的命名类型或映射的名称,用于解析此可选依赖项。如果省略,将解决默认注册问题。该属性是可选的。 |
type |
用于解析可选依赖项映射或注册的类型。必须是与参数或属性的类型兼容的类型。如果不指定类型,Unity 将解析参数或属性的类型。该属性是可选的。 |
<array> 元素
如果参数或属性是数组类型,< array>元素可用于自定义在数组中返回哪些元素。有关更多详细信息,请参阅指定注入值。
< array>元素没有属性。
< array>元素具有零个或多个子元素的集合。如果没有子元素,则注入一个空的、长度为零的泛型和非泛型类型数组。如果有多个子元素,则可以使用任何值元素,例如<dependency>、<optional>或<value>,并且每个元素对应于返回数组中的一个元素。
如果您想拥有数组的默认容器行为,请不要指定 < array>元素;改用<dependency>元素。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <register type="ILogger" mapTo="NetworkLogger"> 2 3 <!-- Empty array --> 4 <property name="noSettings"> 5 <array /> 6 </property> 7 8 <!-- Type NetworkSettings[], get default array injection --> 9 <property name="allSettings" /> 10 11 <!--Type NetworkSettings[], get only the specified three values --> 12 <property name="someSettings"> 13 <array> 14 <dependency name="fastSettings" /> 15 <optional name="turboSettings" /> 16 <value value="port=1234;protocol=tcp;timeout=60” 17 typeConverter="ConnectionSettingsTypeConverter" /> 18 </array> 19 </property> 20 </register>
<extension> 元素
所述<extension>元素用于为Unity容器延长添加到容器中,并且包含延伸部与Unity容器登记的列表。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <container> 2 <extension type="Microsoft.Practices.Unity.Interception.InterceptionExtension, Microsoft.Practices.Unity.Interception" /> 3 </container>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 IUnityContainer container = new UnityContainer(); 2 container.AddNewExtension<MyCustomExtension>();
属性 |
描述 |
---|---|
type |
添加到容器的扩展类型。可以是用户定义的别名或默认别名之一。此属性是必需的。 |
<extension>元素没有子元素。
<instance> 元素
该<instance>元素用于指定值放置在容器中,并表明您不希望由容器创建的价值,但它会利用创建的TypeConverter,然后放置在容器使用RegisterInstance方法。
通过配置添加的实例往往很简单,因为很难用字符串值来表示它们,但如果有一个类型转换器可以处理从字符串的转换,它们就可以任意复杂。
注意:您不能将现有实例与<instance>元素一起使用。该<实例>部分结果中创建一个新的实例,就像与注册东西RegisterType会。这与RegisterInstance的使用形成对比,后者需要用户手动创建实例然后注册它。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <container> 2 <!-- A named string value --> 3 <instance name="NorthwindDb" value="SqlConnectionStringHere" /> 4 5 <!-- A typed value --> 6 <instance type="ConnectionSettings" value="port=1234" typeConverter="ConnectionSettingsTypeConverter" /> 7 </container>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 EmailService myEmailService = new EmailService(); 2 myContainer.RegisterInstance<IMyService>(myEmailService);
属性 |
描述 |
---|---|
name |
注册此实例时使用的名称。该属性是可选的。 |
type |
值的类型。可以是用户定义的别名或默认别名之一。如果省略,则假定类型为System.String。该属性是可选的。 |
value |
传递给类型转换器以创建对象的值。如果省略,则将null传递给类型转换器。该属性是可选的。 |
typeConverter |
用于构造值的类型转换器。如果未指定,则使用值类型的默认转换器。该属性是可选的。 |
<namespace> 元素
所述<命名空间>元素用于声明命名空间,这将是自动搜索类型,如在部分中解释在配置文件中指定类型。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <namespace name="ObjectsInstancesExamples.MyTypes" />
属性 |
描述 |
---|---|
name |
要搜索类型的命名空间的名称。此属性是必需的。 |
所述<命名空间>元素没有允许子元素。
<assembly> 元素
所述<组件>元件用于声明组件,其统一将自动搜索类型,如在部分中描述在配置文件中指定类型。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <assembly name="ObjectsInstancesExamples" />
属性 |
描述 |
---|---|
name |
要搜索的程序集的名称。程序集名称必须充分限定公共语言运行时 (CLR) 才能加载它。例如,GAC 中的程序集必须具有完全限定的程序集名称。此属性是必需的。 |
所述<assembly>元素没有允许子元素。
<alias> 元素
所述<alias>元件被用来定义一个类型别名,如在部分中解释在配置文件中指定类型。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <unity> 2 <alias alias="MyLogger" type="MyNamespace.MyLogger, MyProject" /> 3 <alias alias="AGenericType" type="MyNamespace.MyGenericType`1, MyProject" /> 4 </unity>
属性 |
描述 |
---|---|
alias |
用于引用指定类型的别名。此属性是必需的。 |
type |
别名所指的类型。此名称必须是 CLR 类型名称。别名或自动类型查找不适用于此属性。此属性是必需的。 |
所述<alias>元素没有有效的子元素。
<sectionExtension> 元素
所述<sectionExtension>元素用于加载模式扩展。与用于加载容器扩展对象以修改 Unity 容器实例的运行时行为的<extension>元素不同,该元素加载架构扩展,它修改配置文件本身中允许的元素。这是一个部分级别的元素;它必须出现在任何<container>元素之外。
有关更多详细信息,请参阅扩展 Unity 配置架构。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <unity> 2 <sectionExtension type="MyProject.MySectionExtension, MyProject" /> 3 4 <sectionExtension prefix="ext" type="MyOtherSectionExtension" /> 5 ... 6 </unity>
属性 |
描述 |
---|---|
type |
实现部分扩展的类型。此属性是必需的。 |
prefix |
指定将附加到所有扩展元素的前缀。如果两个不同的扩展添加具有相同名称的元素,这允许您避免冲突。如果省略,则不会添加前缀。该属性是可选的。 |
所述<sectionExtension>元素没有允许子元素。
Unity官方网站 https://dotnetfoundation.org/projects/unitycontainer
Unity官方文档 http://unitycontainer.org/articles/introduction.html
大内老A的博客 https://www.cnblogs.com/artech/p/net-core-di-01.html
Iteye开涛的博客 https://www.iteye.com/blog/jinnianshilongnian-1413846
依赖关系注入指南 https://docs.microsoft.com/zh-cn/dotnet/core/extensions/dependency-injection-guidelines
在 .NET 中使用依赖注入 https://docs.microsoft.com/zh-cn/dotnet/core/extensions/dependency-injection-usage
黄厚镇的博客 https://www.cnblogs.com/hhzblogs/p/9708753.html
田园里的蟋蟀的博客 https://www.cnblogs.com/xishuai/p/3670292.html#xishuai_h7
The Unity Configuration Schema https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ff660914(v=pandp.20)?redirectedfrom=MSDN#config_unity_section