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

ObjectBuilder2 深度解析:動態方法實現構造器注入的 IL 級機制

     編輯:關於.NET

前言:OB2 是什麼?

ObjectBuilder2 (OB2) 是微軟模式與實踐團隊開發的 物件建構與依賴管理框架,Unity 容器即建構於其上。核心特徵:

  • 策略模式 + 責任鏈:建構/銷毀流程由一串 IBuilderStrategy 組成
  • 上下文隔離:IBuilderContext 封裝狀態,策略間傳遞資訊
  • 原則驅動:IBuilderPolicy 提供策略所需配置資料
  • 生命週期管理:ILifetimeContainer 統一釋放 IDisposable
  • 弱引用定位器:IReadWriteLocator 用 WeakReference 避免記憶體洩漏

動態方法構造器注入:核心策略與原則

關鍵角色

類型職責
BuildPlanStrategy建構階段入口,尋找/建立 IBuildPlanPolicy,呼叫 BuildUp
DynamicMethodConstructorStrategy建構動態方法上下文,發射 IL 呼叫構造函數
DefaultDynamicBuilderMethodCreatorPolicy建立動態方法原型:void BuildUp_xxx(IBuilderContext context)
ConstructorSelectorPolicy選擇標記了注入屬性 (如 [InjectionConstructor]) 的構造函數
DynamicMethodBuildPlanCreatorPolicy組裝策略鏈,生成動態方法委託,產出 IBuildPlanPolicy

動態方法上下文

DynamicBuildPlanGenerationContext 結構

封裝:TypeToBuild、DynamicMethod、ILGenerator、區域變數表。

IL 發射邏輯偽碼完整解析

.method public hidebysig virtual instance void BuildUp_"methodname" (IBuilderContext context) cil managed
{
  .maxstack 3
  .locals init (
    [0] class typeToBuild 'existingObjectLocal'
    [1] class [mscorlib]System.String 'currentParameterName'
  )

  L_0000: ldarg.0                    // context
  L_0001: callvirt 'Existing'        // 取得 context.Existing (可能為 null)
  L_0002: cast class typeToBuild
  L_0003: stloc.0                    // existingObjectLocal = context.Existing as typeToBuild

  L_0004: ldloc.0
  L_001f: ldnull
  L_0005: ceq
  L_0006: brfalse existingObjectNotNull  // 若已有實例直接跳過建構

  L_0007: ldarg.0
  L_0008: call 'ThrowForAttemptingToConstructInterface'  // 介面不可實例化拋異常

  L_0009: BeginExceptionBlock
  L_002e: nop
  L_002f: ldstr 'parameters[i].Name'   // 參數名稱 → currentParameterName
  L_0010: stloc.1

  L_0012: ldarg.0                      // context
  L_0013: callvirt 'Policies'          // context.Policies
  L_0014: ldtoken 'typeof(IDependencyResolverPolicy)'
  L_0015: call System.Type.GetTypeFromHandle
  L_0016: ldstr 'key with GUID'        // 參數對應的 BuildKey
  L_0017: callvirt 'IPolicyList.Get'   // 取得 IDependencyResolverPolicy
  L_0018: cast class 'typeof(IDependencyResolverPolicy)'

  L_0019: ldarg.0                      // context
  L_0020: callvirt 'Resolve'           // Resolve 參數值 → 壓入評估堆疊
  L_0021: brtrue L_002e                // 所有參數解析完畢跳出

  L_0022: ldnull
  L_0023: stloc.1                      // 清空 currentParameterName
  L_0024: newobj 'selectedCtor.Constructor' // 呼叫構造函數,實例壓入堆疊
  L_0025: stloc.0                      // 存入 existingObjectLocal

  L_0026: BeginCatchBlock
  exceptionOccuredInResolution:
  L_0027: ldloc.1
  L_0028: ldnull
  L_0029: ceq
  L_0030: brfalse exceptionOccuredInResolution
  L_0031: rethrow                      // 重拋原始異常

  L_0032: ldloc.1                      // 參數名稱
  L_0033: ldstr 'signatureString'      // 簽章資訊
  L_0034: ldarg.0
  L_0035: call 'throwForResolutionFailed' // 包裝拋出解析失敗異常
  L_0036: EndExceptionBlock

  existingObjectNotNull:
}

流程圖解

動態方法建構流程

實戰範例:ThreadPool 建構器

目標類別

public class ThreadPool
{
    private string poolName = string.Empty;
    private int maxThread = 10;

    public ThreadPool() { Console.WriteLine("Default ctor called..."); }

    [InjectionThreadPool]  // 自訂標記屬性
    public ThreadPool(string name, int num)
    {
        this.poolName = name;
        this.maxThread = num;
        OutPut();
    }
    private void OutPut() { /* 顯示名稱與最大執行緒數 */ }
}

自訂參數解析策略

public interface IParameterChooserPolicy : IBuilderPolicy
{
    object GetValue();
}

public class ParameterChooserPolicy<TParameterType> : IParameterChooserPolicy
{
    public virtual object GetValue()
    {
        object obj = ConfigurationManager.AppSettings[typeof(TParameterType).ToString()];
        return Convert.ChangeType(obj, typeof(TParameterType));
    }
}

從 app.config <appSettings> 讀取同名鍵值 (如 "System.String", "System.Int32")。

Builder 組裝類

public class ThreadPoolBuilder<TTypeToBuild> where TTypeToBuild : class
{
    private NamedTypeBuildKey key;
    private StagedStrategyChain<BuilderStage> strategies = new StagedStrategyChain<BuilderStage>();
    private IReadWriteLocator locator;
    private ILifetimeContainer lifetime;

    public ThreadPoolBuilder()
    {
        key = new NamedTypeBuildKey(typeof(TTypeToBuild));
        strategies.Add(new BuildPlanStrategy(), BuilderStage.PreCreation);
        strategies.Add(new ParametersResolveStrategy(), BuilderStage.Creation); // 自訂參數解析
        SetInnerStrategies();
    }

    protected virtual IStagedStrategyChain SetInnerStrategies()
    {
        var inner = new StagedStrategyChain<BuilderStage>();
        inner.Add(new DynamicMethodConstructorStrategy(), BuilderStage.PreCreation);
        return inner;
    }

    public virtual IPolicyList GetPolicies()
    {
        var policies = new PolicyList();
        policies.Set<IBuildPlanCreatorPolicy>(new DynamicMethodBuildPlanCreatorPolicy(SetInnerStrategies()), key);
        policies.Set<IDynamicBuilderMethodCreatorPolicy>(new DefaultDynamicBuilderMethodCreatorPolicy(), key);
        policies.Set<IConstructorSelectorPolicy>(new ConstructorSelectorPolicy<InjectionThreadPoolAttribute>(), key);
        policies.Set<IParameterChooserPolicy>(new ParameterChooserPolicy<string>(), typeof(string));
        policies.Set<IParameterChooserPolicy>(new ParameterChooserPolicy<int>(), typeof(int));
        return policies;
    }

    public TTypeToBuild BuildUp()
    {
        return new Builder().BuildUp<TTypeToBuild>(
            locator, lifetime, GetPolicies(), strategies.MakeStrategyChain(), key, null);
    }
}

使用方式

ThreadPool pool = new ThreadPoolBuilder<ThreadPool>().BuildUp();
// 自動讀取 app.config 中的 System.String / System.Int32 作為建構參數

核心設計心得

  1. 策略即算法封裝:每個 Strategy 只做一件事 (選構造函數、解析參數、發射 IL、建立 Plan),組合出完整建構流程
  2. 原則即配置資料:Policy 以 Key-Value 存儲,Strategy 透過 Key 取用,解耦「做什麼」與「用什麼配置」
  3. 動態方法 = 編譯期生成 IL:比 Reflection 快數量級,Unity 專為高效能注入而引入
  4. 上下文隔離:IBuilderContext 保證策略鏈中狀態不串擾,支援巢狀建構
  5. 擴展點清晰:自訂參數解析只需實作 IParameterChooserPolicy + 註冊 Policy,零修改核心

原始碼下載

Ob2DynamicMethodSolution.rar

總結

OB2 的動態方法構造器注入展示了 框架級基礎設施的極致工藝:用策略鏈組織流程、用 Policy 傳遞配置、用 Reflection.Emit 生成高效能 IL、用上下文隔離狀態。理解這套機制,不僅能深度掌握 Unity 容器內核,更能啟發設計自己的高效能物件建構框架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved