2012-11-10 4 views
6

次の回答は、VS 2010で1、VS 2で2と答えています。私は個人的には2と思っています。私はここで何が起こっているのか分かりません。VS 2010とVS 2012で異なるLINQ回答

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); 
     } 
    } 
} 

ありがとうございます。

+1

Resharper警告:変更された閉鎖へのアクセス –

答えて

16

あなたが見ているのは、foreachという2つの異なるアプリケーションの結果です。動作はVS 2012で変更されました。this articleを参照してください。

foreachループでは、d変数の有効範囲と有効期間が異なります。 VS 2012の前にはdという変数が1つしかありませんでした。つまり、と同じdを参照する2つのクロージャ(s => (s % d == 0)))のコピーを作成しています。ループが評価されると、dは10になります。.Distinct().Count()を呼び出してクエリを実行すると、両方のクロージャでdの値が10になります。カウントが

VS 2012は、各反復ための別の変数を生成し、その各々の閉鎖がd変数の異なる例えば、その特定に対応するものが表示されますVS 2010上1である理由はここにあります繰り返し。

これはおおよそ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))); 
} 

これら2つの違いは容易に理解されるべきです。

あなたはどのVSのバージョンに関係なく、同じ動作を取得しないようにしたい場合は、は常にがあなたの反復変数をコピーします。

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

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

+3

+1。いい答え。 –

+0

詳細情報ブックスありがとう。疑問が出てきた – VVV

+1

@MitchWheat:1つ以上投票が良い答えに残った。 :) – Neolisk

関連する問題