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

C# 2.0 規格深度解析:匿名方法語法、轉換規則與外部變數捕獲機制(上)

     編輯:關於C語言

前言

依據 C# 2.0 規格第 21 節,本文詳細解析 匿名方法表達式 的語法結構、簽名相容性、隱式轉換規則、區塊限制與 外部變數捕獲 機制。

1. 匿名方法表達式語法


anonymous-method-expression:
    delegate anonymous-method-signature_opt block

anonymous-method-signature:
    ( anonymous-method-parameter-list_opt )

anonymous-method-parameter-list:
    anonymous-method-parameter
    anonymous-method-parameter-list , anonymous-method-parameter

anonymous-method-parameter:
    parameter-modifier_opt type identifier
  • 屬於 primary-no-array-creation-expression,歸類為「無型別值」。
  • 定義新的區域變數/常數/參數宣告空間與標籤空間。

2. 匿名方法簽名相容性

匿名方法相容委派型別條件
無簽名 delegate { }委派參數任意,但不可有 out 參數
有簽名 delegate(int x) { }委派參數數量、型別、ref/out 修飾符完全一致 (params 陣列參數不影響相容性)

3. 隱式轉換規則 (核心)

匿名方法 A 隱式轉換為委派型別 D,需滿足:

  1. 參數相容:依上表規則。
  2. 回傳型別相容:
    • D 回傳 void → A 內 return 不可帶運算式。
    • D 回傳 R → A 內所有 return expr 的 expr 必須隱式轉換為 R,且 A 區塊端點不可到達 (確保所有路徑都回傳)。

4. 範例驗證轉換規則


delegate void D(int x);
D d1 = delegate { };           // Ok
D d2 = delegate() { };         // 錯誤:簽名不符
D d3 = delegate(long x) { };   // 錯誤:型別不符
D d4 = delegate(int x) { };    // Ok
D d5 = delegate(int x) { return; }; // Ok
D d6 = delegate(int x) { return x; }; // 錯誤:回傳型別不符 (void)

delegate void E(out int x);
E e1 = delegate { };                    // 錯誤:委派有 out 參數
E e2 = delegate(out int x) { x = 1; };  // Ok
E e3 = delegate(ref int x) { x = 1; };  // 錯誤:ref/out 不符

delegate int P(params int[] a);
P p1 = delegate { };                    // 錯誤:區塊端點可到達
P p2 = delegate { return; };            // 錯誤:回傳型別不符
P p3 = delegate { return 1; };          // Ok
P p4 = delegate { return "Hi"; };       // 錯誤:型別不符
P p5 = delegate(int[] a) { return a[0]; }; // Ok
P p6 = delegate(params int[] a) { return a[0]; }; // 錯誤:不可有 params 修飾符

5. 委派建立運算式替代語法


new D(delegate { Console.WriteLine("hi"); })
// 等價於
(D)delegate { Console.WriteLine("hi"); }

6. 匿名方法區塊限制

  • 參數僅在有簽名時可存取;無簽名時參數不可存取 (但仍可轉換為有參數委派)。
  • 禁止存取最近封閉簽名以外的 ref/out 參數。
  • 結構體中 this 不可存取 (防止值型別複製語意混淆)。
  • 可存取外部變數 (見下節)。
  • 禁止 goto/break/continue 跳出區塊或進入巢狀匿名方法。
  • return 從最近封閉匿名方法返回,非封閉函數成員。

7. 外部變數捕獲機制

7.1 定義

包含匿名方法的作用域內的區域變數、值參數、參數陣列,以及實例方法中的 this,皆為外部變數。

7.2 捕獲與生命週期延長


delegate int D();
static D F()
{
    int x = 0;
    return delegate { return ++x; }; // 捕獲 x
}
static void Main()
{
    D d = F();
    Console.WriteLine(d()); // 1
    Console.WriteLine(d()); // 2
    Console.WriteLine(d()); // 3
}

被捕獲變數生命週期延長至委派可被 GC 回收為止。每次呼叫委派操作同一變數實例。

7.3 實例化時機影響


// 情況 A:變數在迴圈內宣告 → 每次迭代新實例
for (int i = 0; i < 3; i++)
{
    int x = i * 2 + 1;
    result[i] = delegate { Console.WriteLine(x); };
}
// 輸出: 1, 3, 5

// 情況 B:變數在迴圈外宣告 → 共用單一實例
int x;
for (int i = 0; i < 3; i++)
{
    x = i * 2 + 1;
    result[i] = delegate { Console.WriteLine(x); };
}
// 輸出: 5, 5, 5

7.4 多委派共享/獨立捕獲


int x = 0;
for (int i = 0; i < 3; i++)
{
    int y = 0;
    result[i] = delegate { Console.WriteLine($"{++x} {++y}"); };
}
// 輸出: 1 1 / 2 1 / 3 1  (x 共用,y 各自獨立)

7.5 多匿名方法共享同一外部變數


int x = 0;
Setter s = delegate(int v) { x = v; };
Getter g = delegate { return x; };
s(5); Console.WriteLine(g()); // 5
s(10); Console.WriteLine(g()); // 10

結語 (上)

匿名方法透過嚴格的簽名/回傳型別相容規則實現隱式轉換,並以閉包機制捕獲外部變數、延長其生命週期。下篇將續述 匿名方法評估、方法群組轉換 及 編譯器優化 規範。

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