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;
}
posted @ 2015-12-10 16:20  江境纣州  阅读(49)  评论(0编辑  收藏  举报