2016-09-04 1 views
2

Gesetzt ich eine Zeichenfolge, die ich in eine ganze Zahl konvertieren möchten, würde ichWarum muss ich eine Out-Variable initialisieren, wenn Linq mit

int i; 
int.TryParse(someString, out i); 

Jetzt tun würde ich das gleiche in einer Linq zu tun query:

int i; 
var numbers = 
    from s in someStrings 
    where int.TryParse(s, out i) 
    select i; 

Aber diese

CS0165 Verwendung von nicht zugewiesenen lokalen variablen 'i'

mit dem Fehler zu kompilieren verweigert

Es kompiliert und funktioniert wie vorgesehen, wenn ich i auf einen Arbitratwert initialisiere. Aber warum muss ich?

+0

einige Alternativen http://stackoverflow.com/questions/1297231/convert-string-to-int-in-one-line-of-code-using-linq/37033140#37033140 – Slai

+0

Das ist großartig, weil LINQ Funktionen sollen keine Nebenwirkungen erzeugen (dh den Status außerhalb des eigenen Methodenbereichs ändern). C#, das keine strenge funktionale Programmiersprache ist, kann dies nicht erzwingen, aber zumindest ist dies ein Beispiel, wo dies geschieht. Um dies ordentlich zu machen, müssen Sie eine Alternative verwenden, die 'i' im Delegierten (für die Methode' Where') selbst deklariert. –

Antwort

6

Der Abfrageausdruck wird in übersetzt Aufruf, aber der Compiler nicht. Und in der Tat, können Sie ganz einfach Ihre eigene Erweiterungsmethode schreiben, die nicht gehorchten:

public static IEnumerable<T> Where<T>(
    this IEnumerable<T> source, 
    Func<T, bool> predicate) 
{ 
    // I can't be bothered to check the predicate... let's just return everything 
    return source; 
} 

An diesem Punkt mit der normalen Select Anruf, Ihre Stellvertretung i zurückkehren würde, ohne jede Zuweisung einen Wert zu ausgeführt werden.

Grundsätzlich ist die eindeutige Zuordnung Regeln sind bewusst sehr konservativ, unter Vermeidung von Annahmen über die Herstellung, welche Methoden tun usw.

+0

Was wäre der Wert von i, wenn die Where keine Werte ausgewählt? Ich denke, darüber beklagt sich der Compiler. – PhillipH

+0

@PhillipH: Wenn das Prädikat 'Where' bei normalem LINQ immer' false' zurückgibt, wird die 'Select'-Projektion niemals aufgerufen - also wäre das kein Problem. Das Problem ist das Gegenteil - dass der Compiler nicht weiß, dass das 'Where'-Prädikat * immer vor' Select' aufgerufen wird. –

3

Dies wird zu einem Paar Lambda-Ausdrücke kompiliert, die an Where() und Select() übergeben werden.

Der Compiler weiß nicht, was Where() und Select() tun, und nicht nachweisen kann, dass Where() ‚s Lambda wird immer vor Select() laufen.

var numbers = someStrings.Where(s => int.TryParse(s, out i)) 
         .Select(s => i); 

, wissen wir Nun, da die Delegierten aus dem Lambda-Ausdruck für den Anruf werden vor dem Lambda-Ausdruck für die Select erstellt Delegaten ausgeführt werden Where erstellt:

+0

Oder dass Select jemals ausgeführt wird? – PhillipH

+0

@PhillipH: Wenn Select nie ausgeführt wird, gibt es kein Problem. – SLaks

-1

Der Compiler erst zur Laufzeit, ob es wird alle Datensätze zurückgegeben bestimmen kann. Um also einen bestimmten Wert zu haben, muss man eindeutig zugewiesen werden. Denken Sie einfach "Was wäre ich, wenn meine Abfrage keine Zeilen zurückgeben würde?"

+0

Dann wäre die Sequenz leer und der Ausdruck 's => i' Lambda würde nie ausgeführt werden. –

+0

Aber.net kann zur Kompilierzeit nicht feststellen, ob es jemals ausgeführt wird, und dies würde zu der Select-Anweisung führen, die ausgeführt werden kann (soweit der Compiler weiß), die auf einer undefinierten Variablen arbeitet. – PhillipH

+0

Aber das wäre nicht der Fall, wenn die Sequenz leer ist, das ist mein Punkt - die Situation, die Sie vorgeschlagen haben, wäre ein Fall, in dem es * kein Problem war, während es nützlicher ist, einen Fall zu zeigen, der * würde * ein Problem sein. –

Verwandte Themen