C# 2.0 Specification(匿名方法)(二)
2024-07-21 02:20:08
供稿:網(wǎng)友
21.7委托實(shí)例相等性
如下規(guī)則適用由匿名方法委托實(shí)例的相等運(yùn)算符(§7.9.8)和object.equals方法產(chǎn)生的結(jié)果。
l 當(dāng)委托實(shí)例是由具有相同被捕獲外部變量集合的語義相同的匿名方法表達(dá)式計(jì)算而產(chǎn)生時(shí),可以說(但不是必須)它們相等。
l 當(dāng)委托實(shí)例由具有語義不同的匿名方法表達(dá)式,或具有不同的被捕獲外部變量集合時(shí),它們決不相等。
21.8明確賦值
匿名方法參數(shù)的明確賦值狀態(tài)與命名方法是相同的。也就是,引用參數(shù)和值參數(shù)被明確的賦初值,而輸出參數(shù)不用賦初值。并且,輸出參數(shù)在匿名方法正常返回之前必須被明確賦值(§5.1.6)。
當(dāng)控制轉(zhuǎn)換到匿名方法表達(dá)式的程序塊時(shí),對外部變量v的明確賦值狀態(tài),與在匿名方法表達(dá)式之前的v的明確賦值狀態(tài)是相同的。也就是,外部變量的明確賦值將從匿名方法表達(dá)式上下文被繼承。在匿名方法程序塊內(nèi),明確賦值將和在普通程序塊內(nèi)一樣而得到演繹(§5.3.3)。
在匿名方法表達(dá)式之后的變量v的明確賦值狀態(tài)與在匿名方法表達(dá)式之前它的明確賦值狀態(tài)相同。
例如
delegate bool filter(int i);
void f() {
int max;
// 錯(cuò)誤,max沒有明確賦值
filter f = delegate(int n) { return n < max; }
max = 5;
dowork(f);
}
將產(chǎn)生一個(gè)編譯時(shí)錯(cuò)誤,因?yàn)閙ax沒有在匿名方法聲明的地方明確賦值。示例
delegate void d();
void f() {
int n;
d d = delegate { n = 1; };
d();
//錯(cuò)誤,n沒有明確賦值
console.writeline(n);
}
也將產(chǎn)生一個(gè)編譯時(shí)錯(cuò)誤,因?yàn)槟涿椒▋?nèi)n的賦值,對于該匿名方法外部n的明確賦值狀態(tài)沒有效果。
21.9方法組轉(zhuǎn)換
與在§21.3中描述的隱式匿名方法轉(zhuǎn)換相似,也存在從方法組(§7.1)到兼容的委托類型的隱式轉(zhuǎn)換。
對于給定的方法組e和委托類型d,如果允許new d(e)形式的委托創(chuàng)建表達(dá)式(§7.5.10.3 和 §20.9.6),那么就存在從e到d的隱式轉(zhuǎn)換,并且轉(zhuǎn)換的結(jié)果恰好等價(jià)于new d(e)。
在以下示例中
using system;
using system.windows.forms;
class alertdialog
{
label message = new label();
button okbutton = new button();
button cancelbutton = new button();`
public alertdialog() {
okbutton.click += new eventhandler(okclick);
cancelbutton.click += new eventhandler(cancelclick);
...
}
void okclick(object sender, eventargs e) {
...
}
void cancelclick(object sender, eventargs e) {
...
}
}
構(gòu)造函數(shù)用new創(chuàng)建了兩個(gè)委托實(shí)例。隱式方法組轉(zhuǎn)換允許將之簡化為
public alertdialog() {
okbutton.click += okclick;
cancelbutton.click += cancelclick;
...
}
對于所有其他隱式和顯式的轉(zhuǎn)換,轉(zhuǎn)換運(yùn)算符可以用于顯式地執(zhí)行一個(gè)特定的轉(zhuǎn)換。為此,示例
object obj = new eventhandler(mydialog.okclick);
可被代替寫成如下的樣子。
object obj = (eventhandler)mydialog.okclick;
方法組合匿名方法表達(dá)式可以影響重載決策(overload resolution),但它們并不參與類型推斷。請參見§20.6.4獲取更詳細(xì)的信息。
21.10實(shí)現(xiàn)例子
本節(jié)以標(biāo)準(zhǔn)c#的構(gòu)件形式描述匿名方法的可能實(shí)現(xiàn)。在這里描述的實(shí)現(xiàn)基于microsoft c#編譯器所采用的相同原則,但它決不是強(qiáng)制性的或唯一可能的實(shí)現(xiàn)。
本節(jié)的后面部分給出了幾個(gè)示例代碼,它包含了具有不同特性的匿名方法。對于每個(gè)例子,我們將提供使用唯一標(biāo)準(zhǔn)c#構(gòu)件的代碼的對應(yīng)轉(zhuǎn)換。在這些例子中,標(biāo)識符d假定表示如下委托類型。
public delegate void d();
匿名方法的最簡形式就是沒有捕獲外部變量的那個(gè)。
class test
{
static void f() {
d d = delegate { console.writeline("test"); };
}
}
這段代碼可被轉(zhuǎn)換到一個(gè)引用編譯器生成的靜態(tài)方法的委托實(shí)例,而匿名方法的代碼將會放入到該靜態(tài)方法中。、
class test
{
static void f() {
d d = new d(__method1);
}
static void __method1() {
console.writeline("test");
}
}
在下面的示例中,匿名方法引用this的實(shí)例成員。
class test
{
int x;
void f() {
d d = delegate { console.writeline(x); };
}
}
this可以被轉(zhuǎn)換到由編譯器生成的包含匿名方法代碼的實(shí)例方法。
class test
{
int x;
void f() {
d d = new d(__method1);
}
void __method1() {
console.writeline(x);
}
}
在這個(gè)例子中,匿名方法捕獲了一個(gè)局部變量。
class test
{
void f() {
int y = 123;
d d = delegate { console.writeline(y); };
}
}
該局部變量的生存期現(xiàn)在至少必須延長到匿名方法委托的生存期為止。這可以通過將局部變量“提升(lifting)”為編譯器生成的(compiler-generated)類的字段來完成。局部變量的實(shí)例化對應(yīng)于創(chuàng)建一個(gè)編譯器生成的類的實(shí)例,而訪問局部變量將對應(yīng)于訪問編譯器生成的類實(shí)例的一個(gè)字段。并且,匿名方法將成為編譯器生成類的實(shí)例方法。
class test
{
void f() {
__locals1 = new __locals1();
__locals1.y = 123;
d d = new d(__locals1.__method1);
}
class __locals1
{
public int y;
public void __method1() {
console.writeline(y);
}
}
}
最后,如下匿名方法將捕獲this,以及具有不同生存期的兩個(gè)局部變量。
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); };
}
}
}
在這里,編譯器將為每個(gè)語句塊生成類,在這些語句塊中局部變量將被捕獲,而在不同塊中的局部變量將會有獨(dú)立的生存期。
__locals2的實(shí)例,編譯器為內(nèi)部語句塊生成的類,包含局部變量z和引用__locals1實(shí)例的字段。__locals1的實(shí)例,編譯器為外部語句塊生成的類,包含局部變量y和引用封閉函數(shù)成員的this的字段。通過這些數(shù)據(jù)結(jié)構(gòu),你可以通過__locals2的一個(gè)實(shí)例到達(dá)所有被捕獲的局部變量,并且匿名方法的代碼可以作為那個(gè)類的實(shí)例方法而實(shí)現(xiàn)。
class test
{
void f() {
__locals1 = new __locals1();
__locals1.__this = this;
__locals1.y = 123;
for (int i = 0; i < 10; i++) {
__locals2 = new __locals2();
__locals2.__locals1 = __locals1;
__locals2.z = i * 2;
d d = new d(__locals2.__method1);
}
}
class __locals1
{
public test __this;
public int y;
}
class __locals2
{
public __locals1 __locals1;
public int z;
public void __method1() {
console.writeline(__locals1.__this.x + __locals1.y + z);
}
}
}
(匿名方法完)