6

以下は、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);
        }
    }
}

ありがとう。

4

1 に答える 1

16

表示されているのは、の2つの異なるアプリケーションの結果ですforeach。VS2012で動作が変更されました。この記事を参照してください。

2つの違いは、ループ内のd変数のスコープと存続期間に関係します。foreachVS 2012以前は、変数は1つしかありませんでした。つまり、これは、両方が同じdを参照するクロージャ()の2つのコピーを作成していることを意味します。ループの評価が終了した後、は10です。を呼び出してクエリを実行すると、両方のクロージャで。の値が10になります。これが、VS2010でカウントが1である理由です。s => (s % d == 0)) dd.Distinct().Count()d

VS 2012は、反復1ごとに異なる変数を生成するため、クロージャごとに、その特定の反復に対応する変数の異なるインスタンスが表示されます。d

これは、おおよそVS2010が生成するコードです。

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

そして、これはおおよそVS2012が生成するものです。

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

これら2つの違いはすぐに明らかになるはずです。

どのVSバージョンに関係なく同じ動作を取得したい場合は、常に反復変数をコピーしてください。

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

1技術的には、反復変数がクロージャで参照されている場合のみ。そうでない場合は、とにかくクロージャのセマンティクスにのみ影響するため、コピーを作成する必要はありません。

于 2012-11-10T23:53:20.290 に答える