程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C#中派生類的方法裡的匿名delegate調用基類的方法會產生無法驗證的代碼(2)

C#中派生類的方法裡的匿名delegate調用基類的方法會產生無法驗證的代碼(2)

編輯:關於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 {
// do nothing, just to make the compiler happy
// else we'd compiler with /target:library
public static void Main(string[] args) { }
}

用.Net Framework 3.5 Beta 2附帶的C#編譯器(csc.exe)編譯上面的代碼,會得到以下警告:

引用

Microsoft (R) Visual C# 2008 Compiler Beta 2 version 3.05.20706.1 for Microsoft (R) .Net Framework version 3.5

版權所有 (C) Microsoft Corporation。保留所有權利。

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中,引入了匿名delegate的概念,因而可以定義嵌套方法;在C# 3.0中,更進一步引入了Lambda Expression,同樣可以用於定義嵌套方法。這裡,嵌套的方法的作用域遵守詞法作用域,也就是說內部方法可以訪問外部包圍作用域的變量,包括外部的“this”。外部包圍作用域就對嵌套內部方法形成了“閉包”。

由於當一個嵌套方法生成(實例化)後,它的生命周期與它的外部方法不一定相同。它從外部環境中“捕獲”到的變量,就像是從外部“逃逸”出來了一樣。上面的例子中,CharlIE()方法裡x和this都成為了逃逸變量。

這些逃逸變量必須與嵌套方法的生命周期相同,即使外部方法已經返回也不能被立即銷毀;因此這些逃逸變量也不能在棧上分配。這樣,就需要為逃逸變量另外分配空間,常見的做法是在堆上分配。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved