C# Lambdas and “this” variable scope

后端 未结 3 2099
悲&欢浪女
悲&欢浪女 2021-02-19 17:34

I am wondering whether I can use the this keyword inside a C# lambda, although actually I know that I can but I want to make sure that this isn\'t a bad th

3条回答
  •  抹茶落季
    2021-02-19 18:21

    There is nothing wrong with using this in a lambda, but as you mention, if you do use this (or if you use it implicitly, by calling any nonstatic member function or using a nonstatic member variable) then the garbage collector will keep the object that this refers to alive at least as long as the delegate is alive. Since you pass a lambda to Lazy, this implies that the Repository will be alive at least as long as the Lazy object is alive (even if you never call Lazy.Value).

    To demystify it a bit, it helps to look in a disassembler. Consider this code:

    class Foo {
        static Action fLambda, gLambda;
    
        int x;
        void f() {
            int y = 0;
            fLambda = () => ++y;
        }
        void g() {
            int y = 0;
            gLambda = () => y += x;
        }
    }
    

    The standard compiler changes this to the following (try to ignore the <> extra angle brackets). As you can see, lambdas that use variables from inside the function body are transformed into classes:

    internal class Foo
    {
        private static Action fLambda;
        private static Action gLambda;
        private int x;
    
        private void f()
        {
            Foo.<>c__DisplayClass1 <>c__DisplayClass = new Foo.<>c__DisplayClass1();
            <>c__DisplayClass.y = 0;
            Foo.fLambda = new Action(<>c__DisplayClass.b__0);
        }
        private void g()
        {
            Foo.<>c__DisplayClass4 <>c__DisplayClass = new Foo.<>c__DisplayClass4();
            <>c__DisplayClass.<>4__this = this;
            <>c__DisplayClass.y = 0;
            Foo.gLambda = new Action(<>c__DisplayClass.b__3);
        }
    
        [CompilerGenerated]
        private sealed class <>c__DisplayClass1
        {
            public int y;
            public void b__0()
            {
                this.y++;
            }
        }
        [CompilerGenerated]
        private sealed class <>c__DisplayClass4
        {
            public int y;
            public Foo <>4__this;
            public void b__3()
            {
                this.y += this.<>4__this.x;
            }
        }
    
    }
    

    If you use this, whether implicitly or explicitly, it becomes a member variable in the compiler-generated class. So the class for f(), DisplayClass1, does not contain a reference to Foo, but the class for g(), DisplayClass2, does.

    The compiler handles lambdas in a simpler manner if they don't reference any local variables. So consider some slightly different code:

    public class Foo {
        static Action pLambda, qLambda;
    
        int x;
        void p() {
            int y = 0;
            pLambda = () => Console.WriteLine("Simple lambda!");
        }
        void q() {
            int y = 0;
            qLambda = () => Console.WriteLine(x);
        }
    }
    

    This time the lambdas don't reference any local variables, so the compiler translates your lambda functions into ordinary functions. The lambda in p() does not use this so it becomes a static function (called

    b__0); the lambda in q() does use this (implicitly) so it becomes a non-static function (called b__2):

    public class Foo {
        private static Action pLambda, qLambda;
    
        private int x;
        private void p()
        {
            Foo.pLambda = new Action(Foo.

    b__0); } private void q() { Foo.qLambda = new Action(this.b__2); } [CompilerGenerated] private static void

    b__0() { Console.WriteLine("Simple lambda!"); } [CompilerGenerated] private void b__2() { Console.WriteLine(this.x); } // (I don't know why this is here) [CompilerGenerated] private static Action CS$<>9__CachedAnonymousMethodDelegate1; }

    Note: I viewed the compiler output using ILSpy with the option "decompile anonymous methods/lambdas" turned off.

提交回复
热议问题