C#下的lambda代码生成lambdas在循环中 [英] C# under the hood code generation for lambdas within loops

查看:121
本文介绍了C#下的lambda代码生成lambdas在循环中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是基于我最喜欢的海报之一Mehrdad Afshari在关于关闭的问题。

This question is based on the answer given by one of my favourite posters Mehrdad Afshari in this question about closure.

我很难理解为什么C#生成代码的方式......

I am having a hard time understand why C# generates the code the way it does......

以下是有问题的代码

    static void Main(string[] args)
    {

        List<string> list = new List<string> { "hello world",  "TED", "goodbye world" };

        IEnumerable<string> filteredList1 = list;

        IEnumerable<string> filteredList2 = list;

        var keywords = new[] { "hello", "world" };

        foreach (var keyword in keywords)
        {
            //Will execute the following 
            //filteredList1 = filteredList1.Where(item => item.Contains("hello")).Where(item => item.Contains("world"));;
            string value = keyword;
            filteredList1 = filteredList1.Where(item => item.Contains(value));

            //Will execute the following 
            //filteredList2 = filteredList2.Where(item => item.Contains("world"))
            filteredList2 = filteredList2.Where(item => item.Contains(keyword));
        }

        Console.WriteLine("===================================================");
        Console.WriteLine("LIST 1");
        foreach (var s in filteredList1)  // closure is called here
            Console.WriteLine(s);
        Console.WriteLine("===================================================");

        Console.WriteLine("LIST 2");
        foreach (var s in filteredList2)  // closure is called here
            Console.WriteLine(s);
        Console.WriteLine("===================================================");
    }
}

提供以下输出

===============
LIST 1
hello world
===============
LIST 2
hello world
goodbye world
===============

我的问题是,我不明白为什么filteredList2列表不生成与filteredList1相同的代码。
对于foreach(关键字中的var关键字)的每次迭代,应该只是附加另一个.Where(item => item.Contains(关键字))并传递一个复制关键字当前值,似乎更明智。

My problem is that I don't understand why filteredList2 list not generating the same code as filteredList1. It seems more sensible to that with each iteration of the foreach (var keyword in keywords) should just append another .Where(item => item.Contains(keyword)) and pass in a copy keyword current value.

为什么不这样做呢?

编辑:可能我不清楚。我明白何时和如何闭包产生,但我不明白为什么它是这样做。当然,如果一个编译器检测到一个循环变量被使用,那为什么它不能生成一个临时变量,最终最终在与filteredList1相同的情况下有意义。我在这里缺少什么?
可能有一些情况下,你想要将相同的上下文传递给lambda多次,但即使这样,编译器总是使用局部变量来存储循环变量的值作为lambda的上下文。

EDIT : OK maybe I was not clear. I understand When and how the closure generated, however I don't understand WHY it is done like this. Surely it makes sense hat if a compiler detects a loop variable is being used then why can it not generate a temp variable and ultimately end up in the same situation as filteredList1. Am I missing something here? May be there is some scenario where you would want to pass the same context to a lambda multiple times, but even then it always makes sense for the compiler to use local variable to store the value of loop variable when it is used as a context for a lambda.

引用Jon Skeets闭包定义简单来说,闭包允许你封装一些行为,像任何其他对象一样传递它,并且仍然可以访问第一次声明它们的上下文。

To quote Jon Skeets definition of closure "To put it very simply, closures allow you to encapsulate some behaviour, pass it around like any other object, and still have access to the context in which they were first declared."

当然,你们可以看到c#closure over loop变量丢失了它首次设置的循环变量的上下文。

Surely you guys can see that c# closure over loop variable loses the context of the loop variable in which it was first set.

PS请原谅我感冒严重的流感,试图简洁是非常困难的: - )

P.S. Please excuse the waffling I have a severe flu and trying to be concise is very difficult :-)

推荐答案

clousures关闭在变量,而不是值...所以在每次迭代,对于第一个过滤器,你捕获的关键字值在var'value',这是你期望;但对于第二个过滤器,你捕获的迭代变量'关键字',所以在执行它的时候,所有的过滤器有相同的关键字(迭代中的最后一个关键字)'世界',它正确显示两个条目包含世界

You have to remember that clousures close over variables, not values... So on each iteration, for the first filter, you're capturing the keyword value in the var 'value', which is what you're expecting; but for the second filter you are capturing the iteration variable 'keyword', so by the time it gets executed, all the filters have the same value for keyword (the last keyword in the iteration) 'world' and it's correctly showing the two entries that contain 'world'

请查看以下问题以解释

为什么在lambda表达式中使用迭代变量不好用

这篇关于C#下的lambda代码生成lambdas在循环中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆