Unity框架的依赖注入-Dependency injection
一、构造注入 Constructors injection
构造注入适用于对象强依赖的情况,需要在构造函数中实例化别外一个类型,以控制对象的实例化顺序。已经存在的实例是不能使用构造注入,即不能使用构造注入改变实例属性。
以下情况适合使用构造注入
- 在实例化父对象时自动实例化子对象
- 想用一个简单的方法表示代码是类的依赖关系
- 父对象有能在太多的构造函数
- 父对象的构造函数不能有太多的参数
- 需要隐藏对象内部字段的值,而用属性或方法会使其显露
- 要控制父对象依赖的子对象,需要将依赖从代码中移出时
Unity建议当不确定使用哪种注入时,使用构造注入,除非是要在一个已有的对象实例改变属性时才使用其它注入。
DEMO:
namespace ConsoleUnityDemo.ConstractrInjection
{
public class Parent
{
private SubClass subClass;
public Parent(SubClass subInstance)
{
subClass = subInstance;
}
public string SubClassName
{
get {return subClass.ClassName;}
}
}
public class SubClass
{
public string ClassName{get;set;}
}
public class SubClassConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
return base.ConvertTo(context, culture, value, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
SubClass model = new SubClass();
model.ClassName = value.ToString();
return model;
}
return base.ConvertFrom(context, culture, value);
}
}
class Program
{
static void Main(string[] args)
{
UnityConfigurationSection unitySection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
UnityContainer unityContainer = new UnityContainer();
unitySection.Configure(unityContainer, "ConstractInject"); //获取容器
ConstractrInjection.Parent parent = unityContainer.Resolve<ConstractrInjection.Parent>("ParentClass"); //取实例
Console.WriteLine(string.Format(parent.SubClassName));
}
}
}
Unity配置
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <alias alias="Parent" type="ConsoleUnityDemo.ConstractrInjection.Parent, ConsoleUnityDemo" /> <alias alias="SubClass" type="ConsoleUnityDemo.ConstractrInjection.SubClass, ConsoleUnityDemo" /> <alias alias="SubClassConverter" type="ConsoleUnityDemo.ConstractrInjection.SubClassConverter, ConsoleUnityDemo" /> <container name="ConstractInject"> <register type="Parent" name="ParentClass" mapTo ="Parent"> <constructor> <param name="subInstance"> <value value="This is SubClass" typeConverter="SubClassConverter"/> </param> </constructor> </register> </container> </unity> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <appSettings> </appSettings> </configuration>
构造注入存在以下三种情况
- 单个构造函数时自动注入
当对象只有一个构造函数,Unity会自动实例化构造函数参数所依赖的对象,参数必需是个实体类,不能为接口或抽象类。如
public class BoxA { public BoxA(BoxB box) { } }使用Unity注入时会自动实例化BoxB,在上面的Demo中可以不使用<constructor>节点
- 当参数为抽象类或接口时,可以用[Dependency("objectName")]来指定所依赖的对象,Unity在构造MyObject对象时会自动将参数映射到DataServices对象
public class MyObject { public MyObject([Dependency("DataService")] IMyService myDataService) { // work with the service here } }
- 当有多个构造函数,且构造函数的参数个数一样时,使用InjectionConstructor属性指定Unity默认调用的构造函数。Unity对实例化对象时会自动调用标记为InjectionConstructor的构造函数
public class MyObject { public MyObject(SomeOtherClass myObjA) { ... } [InjectionConstructor] public MyObject(MyDependentClass myObjB) { ... } }
二、属性注入Sitter injection
属性注入通入对象公开的属性改变对象的值,比如记录日志时常用的方式,ILogger抽象了日志实体,再根据需要实例化不同的日志实体
public class LogManager { ILogger logInstance; [Dependency] public ILoger { get{return logInstance;} set{logInstance= value;} } public void WriteLog() { logInstance.WriteLog(); } }
用Dependency属性向Unity暴露这是一个依赖注入的属性。
属性注入注意时应该始终在要依赖注入的属性上加上Dependency 标签。(我发现好像不加也是可以用的-_-)
三、方法注入Method Call Injection
属性注入时必需要将对象内部的字段对外公开,但某些时候为了封装原则,不想对外公开这些属性时,可以用方法注入。如用Initialize方法代码Set属性
public class LogManager { ILogger logInstance; [InjectionMethod] public void Initialize(ILogger instance) { logInstance = instance } public void WriteLog() { logInstance.WriteLog(); } }
曾经年少多少事 而今皆付谈笑中!