繼續我們的Unity 1.2使用初探,在上節"Unity 1.2使用初探(1)"中,我們 主要編碼的形式展示了Unity的編碼方式實現。下面我們講討論使用配置文件實現 。
這裡我們繼續使用上節的代碼:
namespace DailyPractice.UnityEx { public interface ILogService { void Write(string message); } public class CnsLogService: ILogService { #region ILogService 成員 public void Write(string message) { Console.WriteLine(String.Format("Cns-exception msg:{0}", message)); } #endregion } public class DataLogService:ILogService { #region ILogService 成員 public void Write(string message) { DailyPractice.Utility.Log.AddLog(message); } #endregion } } namespace DailyPractice.Utility { public class Log { public static void AddLog(string message) { //insert into Log(message) values(@message) Console.WriteLine(String.Format("Data-exception msg:{0}", message)); } } }
這段代碼主要實現了ILogService接口,然後我們以配置文件去實現,編寫如 下的配置文件:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection , Microsoft.Practices.Unity.Configuration" /> </configSections> <unity> <containers> <container name="One"> <types> <type type="DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx" mapTo="DailyPractice.UnityEx.DataLogService, DailyPractice.UnityEx"/> </types> </container> </containers> </unity> </configuration>
這裡我進行相關的說明,configSections配置節的是unity固定配置,通過配 置文件實現Unity,先要進行此配置:
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection , Microsoft.Practices.Unity.Configuration" />
然後,我們在看<unity>裡面的配置:
<containers>是必須元素,其內可有多container個元素,container元 素就是每一個容器的配置,它有一個可選的 name屬性,用於指定容器的名稱。
container元素有下列子元素: types元素 ,instances元素, extensions元 素。
這裡主要說type元素,在文檔中有這麼一句:
The type element defines a type mapping for the Unity container. If you specify a name, that name is used for the type mapping. If you do not specify a name, it creates a default mapping for the specified types. You can specify a lifetime manager for each mapping. If no explicit lifetime manager is configured for a type, transient lifetime management is exercised.
大致的意思就是或type元素定義了一個指向的type,如果你指定了一個name, 那麼就以你指定的來mapping,否則則創建一個一個默認的mapping for the specified types,你還可以指定lifetime manager,如果你不指定,將應用 transient lifetime management。
mapTo是: The actual Type object for the mapTo element in the configuration file.
所以根據以上,可以知道我們是在以 DataLogService 進行 container映射。
然後就是代碼實現了:
namespace DailyPractice.UnityEx { public class UnityConfigEx { public static void Main() { IUnityContainer myContainer = new UnityContainer(); UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); section.Containers[0].Configure(myContainer); ILogService myServiceInstance = myContainer.Resolve<ILogService> (); myServiceInstance.Write("oh,exception occured!"); } } }
執行結果為:
如果我們這樣更改配置節:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection , Microsoft.Practices.Unity.Configuration" /> </configSections> <unity> <containers> <container name="One"> <types> <type type="DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx" mapTo="DailyPractice.UnityEx.CnsLogService, DailyPractice.UnityEx"/> <!--<type type="DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx" mapTo="DailyPractice.UnityEx.DataLogService, DailyPractice.UnityEx"/>--> </types> <instances></instances> <extensions></extensions> </container> </containers> </unity> </configuration>
執行結果為:
如果兩個都配置呢?那麼我們更改配置文件:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection , Microsoft.Practices.Unity.Configuration" /> </configSections> <unity> <containers> <container name="One"> <types> <type type="DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx" name="cnslogger" mapTo="DailyPractice.UnityEx.CnsLogService, DailyPractice.UnityEx"/> <type type="DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx" name="datalogger" mapTo="DailyPractice.UnityEx.DataLogService, DailyPractice.UnityEx"/> </types> <instances></instances> <extensions></extensions> </container> </containers> </unity> </configuration>
修改程序代碼:
namespace DailyPractice.UnityEx { public class UnityConfigEx { public static void Main() { IUnityContainer myContainer = new UnityContainer(); UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); section.Containers[0].Types[0].Configure(myContainer); section.Containers[0].Types[1].Configure(myContainer); IEnumerable<ILogService> myServiceInstances = myContainer.ResolveAll<ILogService>(); foreach (ILogService myServiceInstance in myServiceInstances) { myServiceInstance.Write("haha, you have an exception 了吧!"); } myContainer.Dispose(); } } }
運行結果:
這裡我強調一下:配置節name="cnslogger",在剛剛開始,我沒有指定了,結 果報錯如下
The entry ':DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx' has already been added. (D:\Project\ProjectEx\DailyPractice\UnityEx\bin\Debug\DailyPractice.Uni tyEx.vshost.exe.config line 22)
因為Unity有以下源碼
protected override object GetElementKey(ConfigurationElement element) { UnityTypeElement typeElement = (UnityTypeElement)element; if (typeElement.Name == null) { return typeElement.TypeName; } return typeElement.Name + ":" + typeElement.TypeName; }
如果不指定name,那麼兩個type在循環時就會導致GetElementKey都返回 了':DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx'結果,導致 實例化UnityConfigurationSection異常。
指定name,那麼這兩次實例化分別是:
cnslogger:DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx
datalogger:DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx
UnityConfigurationSection即可實現正確實例化。
本節到此。
歡迎各位指教~~,謝謝