一、構造注入 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(); } }
