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

C# 匿名委派呼叫基類方法導致無法驗證程式碼的深度解析 (二)

     編輯:關於C語言

問題代碼範例

考慮以下代碼片段:

using System;
public delegate void D();
public class Alpha {
    public virtual void Blah() {
        Console.WriteLine("Alpha.Blah");
    }
}
public class Bravo : Alpha {
    public override void Blah() {
        Console.WriteLine("Bravo.Blah");
        base.Blah();
    }
    public void CharlIE() {
        int x = 123;
        D d = delegate {
            this.Blah();
            base.Blah();
            Console.WriteLine(x);
        };
        d();
    }
}
class Program {
    public static void Main(string[] args) { }
}

編譯器警告

使用 .NET Framework 3.5 Beta 2 的 C# 編譯器(csc.exe)編譯上述代碼,會得到警告:

test1.cs(23,13): warning CS1911: 從匿名方法、lambda表達式、查詢表達式或迭代器通過“base”關鍵字訪問成員“Alpha.Blah()”會導致代碼無法驗證。請考慮將這種訪問移入針對包含類型的輔助方法中。

.NET Framework 3.5 RTM 版本結果相同。而 Mono 1.2.5.1 則完全不報錯。

問題根源:閉包與逃逸變數

CharlIE() 方法中使用 this/base 存取自身/基類成員,看似正常。問題出在 C# 處理閉包生成代碼的方式。

C# 2.0 引入匿名委派,C# 3.0 引入 Lambda 運算式,兩者都允許定義巢狀方法。巢狀方法遵循詞法作用域,可存取外部包圍作用域的變數,包括外部的 this,形成「閉包」。

當巢狀方法實例化後,其生命週期可能超過外部方法。它從外部環境「捕獲」的變數,彷彿從外部「逃逸」出來。範例中,x 和 this 都成為逃逸變數。

這些逃逸變數必須與巢狀方法生命週期同步,即使外部方法已返回也不得銷毀,因此不能配置在堆疊上,必須在堆上配置記憶體。編譯器的做法是建立私有巢狀類別來保存這些逃逸變數,並將匿名委派轉為該類別的方法。

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