GetDistinctValuesUsingWhere2

GetDistinctValuesUsingWhere2

这段代码

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication
{
    internal class Program
    {
        public static void Main()
        {
            var values = new[] {1, 2, 3, 3, 2, 1, 4};
            var distinctValues = GetDistinctValuesUsingWhere(values);
            Console.WriteLine("GetDistinctValuesUsingWhere No1: " + string.Join(",", distinctValues));
            Console.WriteLine("GetDistinctValuesUsingWhere No2: " + string.Join(",", distinctValues));
            distinctValues = GetDistinctValuesUsingForEach(values);
            Console.WriteLine("GetDistinctValuesUsingForEach No1: " + string.Join(",", distinctValues));
            Console.WriteLine("GetDistinctValuesUsingForEach No2: " + string.Join(",", distinctValues));
            Console.ReadLine();
        }

        private static IEnumerable<T> GetDistinctValuesUsingWhere<T>(IEnumerable<T> items)
        {
            var set=new HashSet<T>();
            return items.Where(i=> set.Add(i));
        }

        private static IEnumerable<T> GetDistinctValuesUsingForEach<T>(IEnumerable<T> items)
        {
            var set=new HashSet<T>();
            foreach (var i in items)
            {
                if (set.Add(i))
                    yield return i;
            }
        }
    }
}

导致以下输出:



我不明白为什么我在“GetDistinctValuesUsingWhere No2”行中没有得到任何值。

任何人都可以向我解释这一点吗?

UPDATE 在 Scott 的回答之后,我将示例更改为以下内容:
       private static IEnumerable<T> GetDistinctValuesUsingWhere2<T>(IEnumerable<T> items)
    {
        var set = new HashSet<T>();
        var capturedVariables = new CapturedVariables<T> {set = set};

        foreach (var i in items)
            if (capturedVariables.set.Add(i))
                yield return i;
        //return Where2(items, capturedVariables);
    }

    private static IEnumerable<T> Where2<T>(IEnumerable<T> source, CapturedVariables<T> variables)
    {
        foreach (var i in source)
            if (variables.set.Add(i))
                yield return i;
    }

    private class CapturedVariables<T>
    {
        public HashSet<T> set;
    }

这将导致输出 1、2、3、4 的两倍。

但是,如果我只是取消注释该行



并评论这些行



在 GetDistinctValuesUsingWhere2 方法中,我将只获得一次输出 1,2,3,4。这是虽然删除的行和现在未注释的方法完全相同。

我还是没看懂....

最佳答案

回答更新版本:

  • 在包含 GetDistinctValuesUsingWhere2()foreach 方法的情况下
    循环中,返回的 IEnumerable 捕获了闭包中方法的全部内容,包括 set 初始化语句。因此,每次开始迭代可枚举时都会执行此语句,但不会在对 GetDistinctValuesUsingWhere2() 的原始调用期间执行。
  • 在另一个变体的情况下,您返回 Where2()GetDistinctValuesUsingWhere2() 方法不需要捕获方法的内容,因为您没有在其中定义迭代器或委托(delegate)。相反,您将 Where2() 作为 IEnumerable 返回。
    后一种方法只捕获 foreach 循环及其参数(已初始化),而不捕获 set 初始化语句本身。因此,这一次 set 初始化语句将只在原始调用 GetDistinctValuesUsingWhere2() 期间执行一次。

  • 如有必要,在您的代码中的不同点放置一些断点:这应该有助于您理解我在这里试图解释的内容。

    关于c# - where vs. foreach with if - 为什么结果不同?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45887501/

    10-09 02:37