2017-07-27 9 views
2
var counter=0; 
var array = new int[] {0, 1, 2, 3,4}; 

var test = array.Select(a => counter++); 

foreach (var item in test) 
{ 
    Console.WriteLine(item); 
} 

Console.ReadLine(); 

コンソール上でコードを実行すると、0,1,2,3,4が出力されます。 しかし、デバッグモードでテストアレイを展開すると、10から14までの数字が表示されます。なぜですか? また、増分カウンタを返すべきであるので、コンソールが1,2,3,4,5を印刷しない理由を教えてください。C#Linqの異なる値が、デバッグモードで表示された値よりも多く表示される

DebugMode

+4

'array.Select(a => counter ++).ToList()'を使うと、これが止まります! – DavidG

+1

質問の2番目の部分については、++のドキュメントを読むことをお勧めします。https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/increment-operator 'counter ++'はインクリメントする前にcounterを返します。 – Chris

+4

デバッグ中に 'test'を複数回列挙しているため、' counter'がインクリメントされます。 – Lee

答えて

2

出力が変化し続ける理由は、あなたがそれを列挙するまでtestが実際に評価されないということです。そのため、デバッグビューを開くと列挙が評価されます。その後、列挙するたびに、counterの変数が増加するたびに、再度実行されます。したがって、forループを複数回実行するか、またはtest.First()を複数回印刷すると、面白い結果が得られます。

あなたがリストにマテリアライズする列挙を強制することでこれを防ぐことができます:それはゼロから始まり理由については

var test = array.Select(a => counter++).ToList(); 
//          ^^^^^^^^^ 

を、この文脈で++は、それが値を返す意味ポストインクリメント演算子であるので、それはです増分します。 1から始める場合は、代わりに変数にプレフィックスを付けます。

var test = array.Select(a => ++counter).ToList(); 
+0

これはおおよそ私が思ったものですが、私が少し不確かなのは、 'test'の結果が10-14であり、カウンタがインクリメントされているということです。デバッガは故意に実際には列挙型または何かを評価するときにカウンタに変更を持続しない?それは爽やかなものを必要としているようには見えません(現時点ではないと思うと、通常は物事が灰色になります)。 – Chris

+0

@Chris 'counter'が最初に評価され、次に結果ビューを展開した後に' test'が評価されます。 'counter 'の値は、コード行が実行されるまでビュー内で自動的に更新されません。 – DavidG

+0

これは、何らかの理由で 'test'を2回評価したことを示唆しています - カウンタが5で開始したので5-9を返し、次に10-14と見えるものを2回返します。 – Chris

1

これは正常です。 Selectメソッドを使用するだけで、遅延リストが得られます。これは、アクセス時に評価されることを意味します。ここでは、foreachを実行するときに2回アクセスし、デバッガを見るときには、選択したFuncが実行され、カウンタが増えます。 あなたが

var test = array.Select(a => counter++).ToList(); 

により交換した場合それはもう怠け者ではありません、あなたがToListメソッド()を呼び出したときに一度だけ実行されます。しかし、いくつかの条件を後で追加するなど、条件を追加したい場合は、作成を完了する前にクエリを実行したくない場合には、特に遅延を抑えることは面白いかもしれません。

カウンタ++は最初に値を与えてからインクリメントするため、ゼロから開始します。あなたが1から始めるには、カウンターを1に初期化するか、カウンター++を++カウンターに置き換えるかのいずれかを行うことができます。最初にインクリメントされてから返されます。

関連する問題