首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Unity 1.2 依賴注入實戰(二):XML 組態檔配置詳細指南

     編輯:關於.NET

承接《Unity 1.2 依賴注入實戰(一)》,本文將深入探討如何透過 XML 組態檔來配置 Unity 容器,實現型別對應的外部化管理,避免硬式編碼帶來的維護困擾。

範例基礎架構

沿用上篇的介面與實作類別:

public interface ILogService {
    void Write(string message);
}

public class CnsLogService : ILogService {
    public void Write(string message) {
        Console.WriteLine($"Cns-exception msg:{message}");
    }
}

public class DataLogService : ILogService {
    public void Write(string message) {
        DailyPractice.Utility.Log.AddLog(message);
    }
}

namespace DailyPractice.Utility {
    public class Log {
        public static void AddLog(string message) {
            Console.WriteLine($"Data-exception msg:{message}");
        }
    }
}

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>
    <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 組態區塊處理器,type 屬性固定指向 UnityConfigurationSection。
<containers> / <container>
容器集合與單一容器定義。name 屬性為選填,用於識別多容器場景。
<types> / <type>
型別對應集合。type 指定介面或基底類別,mapTo 指定具體實作類別。

根據官方文件:type 元素定義容器的型別對應。若指定 name 則建立具名對應,否則建立預設對應。可為每個對應指定生命週期管理器,預設為 transient(瞬時模式,每次解析建立新實例)。

程式碼載入組態並解析

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!");
}

執行結果將呼叫 DataLogService.Write,輸出 Data-exception msg:oh,exception occured!。

進階場景:多重實作與具名解析

情境一:切換實作類別

修改 mapTo 指向 CnsLogService,重新執行即可切換行為,無需改動程式碼。

情境二:同時註冊多個實作

<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>

關鍵點:必須指定 name 屬性區分不同對應,否則 Unity 內部 GetElementKey 會產生相同鍵值導致例外:

The entry ':DailyPractice.UnityEx.ILogService, DailyPractice.UnityEx' has already been added.

程式碼解析所有具名實例

section.Containers[0].Types[0].Configure(myContainer);
section.Containers[0].Types[1].Configure(myContainer);

IEnumerable<ILogService> myServiceInstances = myContainer.ResolveAll<ILogService>();
foreach (var svc in myServiceInstances) {
    svc.Write("haha, you have an exception 了吧!");
}

輸出將包含兩個實作的寫入結果。

核心原理補充

Unity 組態區塊內部透過 UnityTypeElement 的 GetElementKey 產生唯一鍵:

protected override object GetElementKey(ConfigurationElement element) {
    var typeElement = (UnityTypeElement)element;
    if (typeElement.Name == null) {
        return typeElement.TypeName;  // 無 name 時僅用型別名稱
    }
    return typeElement.Name + ":" + typeElement.TypeName;  // 有 name 時組合
}

因此,同一介面的多重對應必須指定 name 避免鍵值衝突。

總結

  • XML 組態實現型別對應外部化,支援無重新編譯切換實作
  • name 屬性是多重對應的關鍵,亦是 ResolveAll 正常運作的前提
  • 適合需頻繁調整依賴關係、多環境部署的企業級應用
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved