linq - VS 2010和VS 2012中的不同LINQ答案

标签 linq ienumerable lazy-evaluation

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

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中,行为已更改。请参阅this article

两者之间的差异涉及d循环中foreach变量的范围和生存期。在VS 2012之前,只有一个d变量,所以这意味着您要创建两个闭包的副本(s => (s % d == 0))),它们都引用相同的d。在评估完循环之后,d为10。当您通过调用.Distinct().Count()执行查询时,两个闭包的d都将看到值为10。这就是为什么在VS 2010上计数为1的原因。

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

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

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

这大致是VS 2012生成的:
for (int _index = 0; _index < divisors.Length; ++_index) {
    int d = divisors[_index];
    m = m.Concat(nums.Where(s => (s % d == 0)));
}

两者之间的区别应该显而易见。

如果无论哪个VS版本都希望获得相同的行为,请始终复制您的迭代变量:
foreach (int d in divisors)
{
    var copy = d;
    m = m.Concat(nums.Where(s => (s % copy == 0)));
}

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

关于linq - VS 2010和VS 2012中的不同LINQ答案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13327224/

相关文章:

c# - 仅当第二个 TSource 不为 Null 时联合集合

c# - SortedSet - 存储类对象时的自定义顺序

java - 在分离之前用 JPA 完全加载实体?

swift - 将多个调用链接到同一方法时出现编译器问题

javascript - 在 lodash.js 中,它会缓存 `.value()` 方法的结果吗?

c# - 转变 ? : statement to handle more than 2 answers

linq - 获取所有中间元素 IEnumerable LINQ

c# - 获取日期期间查询内的最大版本

c# - 用于差异集的 LINQ

c# - 无法将类型 'int' 隐式转换为 'System.Collections.Generic.List<QuickTest.Stock>'