Lambda表达式中变量的作用域(转载)
转载自http://www.cnblogs.com/smwikipedia/archive/2009/05/06/1450825.html
在Lambda式定义中可以引用外部变量。只要是在定义处能够访问到的变量,都可以在Lambda式中引用。
Lambda式的定义仅仅是定义一个匿名方法,最终会生成一个委托对象。外部变量的引用将被“捕获”到委托对象内部,将会伴随委托对象的整个生命周期。在委托对象生命周期结束之前该变量都不会被垃圾回收。就算外部变量已经超过了原来的作用域,也还能继续在
Lambda式中使用。所有会被引用的外部变量必须在Lambda式定义之前被显示赋值。
delegate void Del(); delegate bool Del2(int i); class Test { public Del myDel; public Del2 myDel2; public void CallDel() { int j = 0 ; myDel = () => { j = 10;}; Console.WriteLine("j={0}", j); myDel(); Console.WriteLine("j={0}", j); myDel2 = (x) => { return x == j; }; // j = 10 } }
class Program { static void Main(string[] args) { Test test = new Test(); test.CallDel(); bool result = test.myDel2(10); Console.WriteLine(result); // True Console.ReadKey(); } }
test.myDel2(10)为True的原因是匿名函数生成委托对象,委托对象含有一个成员变量就是局部变量j的值。
用.Net Reflector的C# None解析如下:
public void CallDel() { <>c__DisplayClass2 class2; class2 = new <>c__DisplayClass2(); class2.j = 0; this.myDel = new Del(class2.<CallDel>b__0); Console.WriteLine("j={0}", (int) class2.j); this.myDel(); Console.WriteLine("j={0}", (int) class2.j); this.myDel2 = new Del2(class2.<CallDel>b__1); return; }
发现CallDel函数中没有局部变量j,只有一个委托对象c__DisplayClass2的成员变量j。c__DisplayClass2的代码如下:
[CompilerGenerated] private sealed class <>c__DisplayClass2 { // Fields public int j; // Methods public <>c__DisplayClass2(); public void <CallDel>b__0(); public bool <CallDel>b__1(int x); }
<CallDel>的意思应该是委托的,但是可以看出来c__DisplayClass2类里有成员变量j,和两个方法b_0和b_1;
==============================================================================
假如在CallDel()方法最后加一个j=11,是否会使c__DisplayClass2中的j=11呢,还是在CallDel()方法中新加一个变量j,查看代码如下:
public void CallDel() { int j = 0 ; myDel = () => { j = 10;}; Console.WriteLine("j={0}", j); myDel(); Console.WriteLine("j={0}", j); myDel2 = (x) => { return x == j; }; // j = 10 j = 11; }
public void CallDel() { <>c__DisplayClass2 class2; class2 = new <>c__DisplayClass2(); class2.j = 0; this.myDel = new Del(class2.<CallDel>b__0); Console.WriteLine("j={0}", (int) class2.j); this.myDel(); Console.WriteLine("j={0}", (int) class2.j); this.myDel2 = new Del2(class2.<CallDel>b__1); class2.j = 11; return; }
可知结果是class2.j=11;
所以在Lambda表达式中使用的变量最好不要用外部变量,如果在复杂的函数中就会混淆,不利于理解。
public void CallDel() { myDel = () => { int j = 10; Console.WriteLine("j={0}",j); }; myDel(); myDel2 = (x) => { int j = 10; return x == j; }; }
这样就没有c__DisplayClass2类了,只有一个委托方法,代码如下:
internal class Test { // Fields [CompilerGenerated] private static Del CS$<>9__CachedAnonymousMethodDelegate2; [CompilerGenerated] private static Del2 CS$<>9__CachedAnonymousMethodDelegate3; public Del myDel; public Del2 myDel2; // Methods public Test(); [CompilerGenerated] private static void <CallDel>b__0(); [CompilerGenerated] private static bool <CallDel>b__1(int x); public void CallDel(); }
b_0方法的代码如下:
[CompilerGenerated] private static void <CallDel>b__0() { int num; num = 10; Console.WriteLine("j={0}", (int) num); return; }
b_1方法的代码如下:
[CompilerGenerated] private static bool <CallDel>b__1(int x) { int num; bool flag; num = 10; flag = x == num; Label_000B: return flag; }