2012-11-10 10 views
6

Das folgende gibt Antwort als 1 in VS 2010 und 2 in VS 2012. Ich persönlich denke, es sollte 2. Ich bin mir nicht sicher, was hier vor sich geht.Verschiedene LINQ Antwort in VS 2010 und VS 2012

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

Danke.

+1

Nachschärfwarnung: Zugang zu modifiziertem Verschluss –

Antwort

16

Was Sie sehen, ist das Ergebnis von zwei verschiedenen Anwendungen von foreach. Das Verhalten wurde in VS 2012 geändert. Siehe this article.

Der Unterschied zwischen den beiden beinhaltet den Umfang und die Lebensdauer der d Variable in der foreach Schleife. Vor VS 2012 gab es nur eine d Variable, was bedeutet, dass Sie zwei Kopien eines Verschlusses erstellen (s => (s % d == 0))), die beide die selbed referenzieren. Nachdem die Schleife ausgewertet wurde, ist d 10. Wenn Sie die Abfrage ausführen, indem Sie .Distinct().Count() aufrufen, sehen beide Schließungen einen Wert von 10 für d. Aus diesem Grunde ist die Anzahl 1 auf VS 2010

VS 2012 erzeugt eine andere Variable für jede Iteration 1, so dass jede Schließung sieht eine verschiedene Instanz des d Variable, die eine, die zu diesem bestimmten entspricht Iteration. Diese

ist in etwa der Code, der VS 2010 erzeugt:

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

Und das ist ungefähr das, was VS 2012 erzeugt:

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

Der Unterschied zwischen diesen beiden sollte leicht ersichtlich sein.

Wenn Sie möchten, egal das gleiche Verhalten erhalten, die VS-Version, dann immer Ihre Iterationsvariable kopieren:

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

Technisch nur, wenn die Iterationsvariable referenziert wird in ein Verschluss. Ist dies nicht der Fall, muss keine Kopie erstellt werden, da dies ohnehin nur die Semantik des Abschlusses betrifft.

+3

+1. gute Antwort. –

+0

Danke für die ausführliche Info bro. Zweifel wurden ausgeräumt. – VVV

+1

@MitchWheat: noch eine Stimme übrig zu nette Antwort. :) – Neolisk