問題

このコード

 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 No1:1,2,3,4

GetDistinctValuesUsingWhere NO2:

GetDistinctValuesUsingForEach No1:1,2,3,4

GetDistinctValuesUsingForEach NO2:1,2,3,4

なぜ私は "GetDistinctValuesUsingWhere NO2"の行に値を取得しないのか分かりません。

誰も私にこれを説明することはできますか?

スコットからの回答の後に更新しました。この例を次のように変更しました。

        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の2倍になります。

しかし、行のコメントを外すだけで

Where2(項目、変数)を返します。

行をコメントする

foreach(アイテム内のvar i) if(capturedVariables.set.Add(i)) yield return i;

GetDistinctValuesUsingWhere2メソッドでは、出力1,2,3,4を1回だけ取得します。これは削除された行が非常に難しく、now-uncommentedメソッドはまったく同じです。

まだ分からない...。

  ベストアンサー

更新されたバージョンに答える:

  • foreachを含むGetDistinctValuesUsingWhere2()メソッドの場合 ループ、返されたIEnumerableは、set初期化ステートメントを含むクロージャ内のメソッドの内容全体をキャプチャしました。したがって、このステートメントは、GetDistinctValuesUsingWhere2()への元の呼び出し中には実行されません。
  • Where2()を返す他の変種の場合、GetDistinctValuesUsingWhere2()メソッドは、イテレータまたはデリゲートを定義していないため、メソッドの内容をキャプチャする必要はありません。代わりに、IEnumerableとしてWhere2()を返します。 後者のメソッドは、foreachループとそのパラメータ(すでに初期化されている)だけをキャプチャしますが、set初期化ステートメント自体はキャプチャしません。したがって、今回は、GetDistinctValuesUsingWhere2()への元の呼び出し中に、set初期化ステートメントが1回だけ実行されます。

必要に応じて、コード内のさまざまなポイントにブレークポイントを置く:これは私がここで説明しようとしたことを理解するのに役立ちます。

  同じタグがついた質問を見る

c#.netclosures