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

C# 2.0 匿名方法規範深度解析(二):委托相等性、明確賦值與方法組轉換

     編輯:關於C#

繼上一篇介紹匿名方法語法與轉換規則後,本文繼續深入 C# 2.0 規範中關於匿名方法的委托實例相等性、明確賦值規則、方法組隱式轉換以及編譯器實現範例。

21.7 委托實例相等性

規範定義了由匿名方法產生的委托實例在相等運算符(==)與 object.Equals 下的行為:

  • 可能相等:若兩個委托實例由語義相同的匿名方法表達式產生,且捕獲的外部變量集合相同,則它們 可以 相等(但不強制)。
  • 絕不相等:若匿名方法語義不同,或捕獲的外部變量集合不同,則委托實例永不相等。

此規則允許編譯器對語義相同且捕獲相同變量的匿名方法進行優化,返回同一委托實例。

21.8 明確賦值規則

匿名方法對外部變量的明確賦值狀態遵循以下原則:

  • 進入匿名方法塊時,外部變量的明確賦值狀態與外部上下文一致(即繼承外部狀態)。
  • 在匿名方法塊內,明確賦值分析與普通塊相同。
  • 離開匿名方法表達式後,變量的明確賦值狀態恢復為進入前的狀態(匿名方法內部的賦值不影響外部)。

錯誤範例 1:使用未賦值的外部變量

delegate bool Filter(int i);
void F() {
    int max;
    // 錯誤:max 在匿名方法聲明處未明確賦值
    Filter f = delegate(int n) { return n < max; };
    max = 5;
    DoWork(f);
}

錯誤範例 2:匿名方法內賦值不影響外部狀態

delegate void D();
void F() {
    int n;
    D d = delegate { n = 1; };
    d();
    // 錯誤:n 在此處仍視為未明確賦值
    Console.WriteLine(n);
}

21.9 方法組轉換

類似匿名方法的隱式轉換,方法組(method group)也存在到兼容委托類型的隱式轉換。若 new D(E) 合法,則 E 隱式轉換為 D,等價於 new D(E)。

此特性簡化了事件訂閱語法:

// 原寫法
okButton.Click += new EventHandler(OkClick);
// 簡化後
okButton.Click += OkClick;

方法組與匿名方法均可參與多載決策,但不參與類型推斷。

21.10 編譯器實現範例

規範以標準 C# 結構演示編譯器可能的降級實現(非強制性):

情況 1:無捕獲變量 → 靜態方法

class Test {
    static void F() {
        D d = delegate { Console.WriteLine("test"); };
    }
}
// 降級為
class Test {
    static void F() { D d = new D(__Method1); }
    static void __Method1() { Console.WriteLine("test"); }
}

情況 2:捕獲 this 實例成員 → 實例方法

class Test {
    int x;
    void F() { D d = delegate { Console.WriteLine(x); }; }
}
// 降級為
class Test {
    int x;
    void F() { D d = new D(__Method1); }
    void __Method1() { Console.WriteLine(x); }
}

情況 3:捕獲局部變量 → 提升為編譯器生成類的字段

局部變量生命週期必須延長至委托存活期間,編譯器生成封裝類 __Locals1,將變量提升為字段,匿名方法轉為該類的實例方法。

class Test {
    void F() {
        int y = 123;
        D d = delegate { Console.WriteLine(y); };
    }
}
// 降級為
class Test {
    void F() {
        __Locals1 __locals1 = new __Locals1();
        __locals1.y = 123;
        D d = new D(__locals1.__Method1);
    }
    class __Locals1 {
        public int y;
        public void __Method1() { Console.WriteLine(y); }
    }
}

情況 4:捕獲 this 與多層塊局部變量 → 巢狀封裝類

不同作用域的局部變量對應不同封裝類,內層類持有外層類引用,形成鏈式結構。

class Test {
    int x;
    void F() {
        int y = 123;
        for (int i = 0; i < 10; i++) {
            int z = i * 2;
            D d = delegate { Console.WriteLine(x + y + z); };
        }
    }
}
// 降級為 __Locals1(含 this、y)與 __Locals2(含 z、__Locals1 引用)

結語

理解匿名方法的編譯器降級機制,不僅有助於掌握閉包語義、變量捕獲與生命週期,更能在性能調優與除錯時提供關鍵洞見。下一篇將探討 C# 3.0 引入的 Lambda 表達式如何進一步簡化此模式。

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