How does lambdas cover local variables?

So my understanding of how the compiler handles lambdas is limited.

I understand that the compiler takes your lambda and turns it into a real method.

If so, how does it apply to local variables?

    public async Task<dynamic> GetWebStuff()
    {
        dynamic ret = "";

        WebClient wc = new WebClient();          

        wc.DownloadStringCompleted += async (s, a) => 
        {
            ret = await Newtonsoft.Json.JsonConvert.DeserializeObject(a.Result.ToString());
        };

        wc.DownloadString("http://www.MyJson.com");

        return ret;
    }

The above example sets the return value ret for the calling object, which is a dynamic object of deserialized JSON.

How does this happen if the compiler takes a completed lambda event and abstracts it into its own method? How to find out how to set the value of ret?

I like it when I say this (which obviously doesn't work)

        public async Task<dynamic> GetWebStuff()
        {
            dynamic ret = "";

            WebClient wc = new WebClient();

            wc.DownloadStringCompleted += wc_DownloadStringCompleted;            

            wc.DownloadString("google.com");

            return ret;
        }

        void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            ret = await Newtonsoft.Json.JsonConvert.DeserializeObject(e.Result.ToString());
        }
+4
source share
3 answers

. , :

int x = 0;

Action action = () => x = 2;

action();

Console.Write(x);

:

enter image description here

IL- <Main>b__2, x:

    .method assembly hidebysig instance void 
        '<Main>b__2'() cil managed
{
  // Code size       10 (0xa)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.2
  IL_0002:  stfld      int32 ConsoleApplication1.Program/'<>c__DisplayClass0'::x
  IL_0007:  br.s       IL_0009
  IL_0009:  ret
} // end of method '<>c__DisplayClass0'::'<Main>b__2'
+9

, ​​, , , , (mono?). , - closure.

Wiki:

( ) - , ( upvalues) function 1 - - , .

+5

, -, . , , .

ret , . , , , , .

, GetWebStuff , , " " " [...]". , , , , , .

:

public Task<dynamic> GetWebStuff()
{
    var tcs = new TaskCompletionSource<dynamic>();

    WebClient wc = new WebClient();

    wc.DownloadStringCompleted += async (s, a) =>
    {
        tcs.TrySetResult(await Newtonsoft.Json.JsonConvert.DeserializeObject(
            a.Result.ToString()));
    };

    wc.DownloadStringAsync(new Uri("http://www.MyJson.com"));

    return tcs.Task;
}

, , , .

, , , :

class ClosureClass
{
    public TaskCompletionSource<dynamic> tcs;
    public async Task AnonymousMethod1(object s, 
        DownloadDataCompletedEventArgs a)
    {
        tcs.TrySetResult(await Newtonsoft.Json.JsonConvert.DeserializeObject(
            a.Result.ToString()));
    }
}

public Task<dynamic> GetWebStuff()
{
    ClosureClass closure = new ClosureClass();
    closure.tcs = new TaskCompletionSource<dynamic>();

    WebClient wc = new WebClient();

    wc.DownloadStringCompleted += closure.AnonymousMethod1;

    wc.DownloadStringAsync(new Uri("http://www.MyJson.com"));

    return closure.tcs.Task;
}

When a variable is closed, a new closure class is created with an instance variable for each private variable. The lambda turns into an instance method that uses these instance fields. The method that the lambda had creates an instance of this new type, uses its fields, not local ones, wherever they are closed above the locales, and then uses the new named method where the lambda was.

+3
source

Source: https://habr.com/ru/post/1542226/


All Articles