VS 2010和VS 2012中的不同LINQ答案 [英] Different LINQ Answer in VS 2010 and VS 2012

查看:71
本文介绍了VS 2010和VS 2012中的不同LINQ答案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下给出的答案在VS 2010中为1,在VS 2012中为2.我个人认为应该为2.我不确定这里发生了什么.

The following gives answer as 1 in VS 2010 and 2 in VS 2012. I personally think it should be 2. I am not sure what's going on here.

using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;

namespace _335ExamPreparation
{
    public class Doubts
    {
        int[] nums = { 10, 11, 12, 13, 14, 15, 16 };
        int[] divisors = { 7, 10 };

        static void Main(string[] args)
        {
            Doubts d = new Doubts();
            d.func();
        }

        public void func()
        {
            var m = Enumerable.Empty<int>();
            foreach (int d in divisors)
            {
                m = m.Concat(nums.Where(s => (s % d == 0)));
            }

            int count = m.Distinct().Count();
            Console.WriteLine(count);
        }
    }
}

谢谢.

推荐答案

您看到的是foreach的两个不同应用程序的结果.在VS 2012中,该行为已更改.请参见

What you're seeing is the result of two different applications of foreach. The behavior was changed in VS 2012. See this article.

两者之间的区别涉及foreach循环中d变量的范围和生存期.在VS 2012之前,只有一个d变量,因此,这意味着您要创建两个闭包(s => (s % d == 0)))的两个副本,两个副本都引用 same d.循环完成评估后,d为10.通过调用.Distinct().Count()执行查询时,两个闭包对于d的值均为10.这就是为什么VS 2010的计数为1的原因.

The difference between the two involves the scope and lifetime of the d variable in the foreach loop. Before VS 2012, there was only one d variable, so what this means is that you are creating two copies of a closure (s => (s % d == 0))) that both reference the same d. After the loop finishes being evaluated, d is 10. When you execute the query by calling .Distinct().Count(), both closures will see a value of 10 for d. This is why the count is 1 on VS 2010.

VS 2012为每次迭代 1 生成一个不同的变量,因此每个闭包将看到变量的不同实例,该实例对应于该特定变量.迭代.

VS 2012 generates a different variable for each iteration1, so each closure will see a different instance of the d variable, the one that corresponds to that particular iteration.

这大致是VS 2010生成的代码:

This is roughly the code that VS 2010 generates:

int d;
for (int _index = 0; _index < divisors.Length; ++_index) {
    d = divisors[_index];
    m = m.Concat(nums.Where(s => (s % d == 0)));
}

这大致是VS 2012生成的:

And this is roughly what VS 2012 generates:

for (int _index = 0; _index < divisors.Length; ++_index) {
    int d = divisors[_index];
    m = m.Concat(nums.Where(s => (s % d == 0)));
}

这两者之间的区别应该很明显.

The difference between these two should be readily apparent.

如果无论哪个VS版本都希望获得相同的行为,请始终复制您的迭代变量:

If you want to get the same behavior no matter which VS version, then always copy your iteration variable:

foreach (int d in divisors)
{
    var copy = d;
    m = m.Concat(nums.Where(s => (s % copy == 0)));
}


1 从技术上讲,仅当迭代变量在闭包中被引用时.如果不是,则无需进行复制,因为这只会影响闭包语义.


1 Technically, only if the iteration variable is referenced in a closure. If it's not then there is no need to make a copy as this only affects closure semantics anyway.

这篇关于VS 2010和VS 2012中的不同LINQ答案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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