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

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

編輯:關於C語言

引用

Microsoft (R) .Net Framework PE VerifIEr. Version 3.5.20706.1
Copyright (c) Microsoft Corporation. All rights reserved.
[IL]: Error: [F:\FX\share\testClosure.exe : Bravo+<>c__CompilerGenerated0::<CharlIE>c__1][offset 0x00000011] The 'this' parameter to the call must be the calling method's 'this' parameter.
1 Error Verifying testClosure.exe

錯誤所對應的IL代碼為:

Java代碼

IL_0011: call instance void Alpha::Blah()

也就是原本的base.Blah()。

一個有趣的觀察:雖然C#的語言規范中沒有說明具體該如何為閉包生成代碼,但.NET Framework與Mono所做的幾乎是一樣的。這大概是因為Mono要盡量保持與.Net Framework的兼容吧。

前面的例子是用匿名delegate,在C# 3.0中換成Lambda Expression也一樣:

C#代碼

public void CharlIE( ) { // int x = 123;
int x = 123;
D d = ( ) =&gt; {
this.Blah( );
base.Blah( );
Console.WriteLine( x );
};
d( );
}

上面提到了編譯器會生成不可驗證代碼的狀況。不過要是把前面例子中CharlIE()裡的x給去掉,變成這樣的話:

C#代碼

public void CharlIE( ) {
D d = delegate {
this.Blah( );
base.Blah( );
};
d( );
}

那麼.Net Framework的C#編譯器能發現唯一的逃逸變量是this,於是不會生成一個私有的內部類,而是直接將那個匿名delegate生成為Bravo的一個私有成員方法。也就是生成類似這樣的代碼:

C#代碼

public class Bravo : Alpha {
public override void Blah() {
Console.WriteLine(&quot;Bravo.Blah&quot;);
base.Blah();
}

// compiler generated method
public void __method() {
this.blah();
// on the next line, no such &quot;__nonvirtual__&quot; in C#
__nonvirtual__ ((Alpha)this).Blah());
}

public void CharlIE() {
D d = new D(this.__method);
d();
}
}

換句話說,當逃逸變量只有this時,編譯器並不會生成不可驗證的變量。不過為了外表上行為的一致性,.Net Framework的C#編譯器仍然會給出跟上面一樣的警告。

Mono方面則是沒有做這樣的優化,仍然會與前面所說的狀況一樣,生成不可驗證的代碼。

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