2010-01-07 12 views
8

Ersetzen habe ich eine LINQ-Abfrage, die wie folgt aussieht Klausel stattdessen.ein reguläres Verfahren mit einer anonymen Methode in C#/LINQ

Ich versuchte ...

... 
select 
    (f, b) => { f.MissingProp = b.MissingProp; return f } 

... aber ich habe den folgenden Fehler:

A local variable named 'f' cannot be declared in this scope because it would give a different meaning to 'f', which is already used in a 'parent or current' scope to denote something else.

Wie kann ich "Lambda-ize" meine Frage?


aktualisieren

Das funktioniert auch nicht:

... 
select 
    () => { f.MissingProp = b.MissingProp; return f } 

ich die folgende Fehlermeldung erhalten:

The type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'Join'.

ich die join Klausel nicht geändert zu alles, also bin ich perplex.

+1

Ich kenne die LINQ-Syntax nicht gut genug, um es auszu schreiben, aber wäre es nicht besser, mutieren in einer foreach (yourLinqQuery) -Anweisung? Wenn eine Auswahl mutiert ist, erscheinen die Objekte verwirrend. –

+0

versuchen * auf f.BarId gleich b.Id * –

+0

@Doc Brown, das war eigentlich nur ein Tippfehler in meinem Beispiel (mein realer Code sagt 'equals'). Jetzt behoben. – devuxer

Antwort

3

Sie können Ihren Parametern in einem Lambda-Ausdruck Typen geben, aber Sie müssen andere Namen verwenden, da Sie in der Abfrage bereits f und b verwenden.

(Foo f1, Bar b1) => ...

bearbeiten

return 
(
    from 
     f in foos 
    join 
     b in bars 
     on f.BarId equals b.Id 
    select 
     new {f, b} 
).select(foobar => {foobar.f.BarId = foobar.b.Id; return foobar.f}); 
+0

das würde auch nicht funktionieren. –

+0

Dies funktioniert nicht. Es weiß nicht, dass es "f" und "b" geben sollte. Ich bekomme auch den gleichen Fehler, wenn ich '() => {...}' (siehe mein Update) benutze. – devuxer

+0

Siehe meine Bearbeitung bitte ... –

1

wählen (f2, b2) => {f2.MissingProp = b2.MissingProp; return f2}

+0

das würde nicht funktionieren. –

+0

Dies funktioniert nicht. Es weiß nicht, dass es "f" und "b" geben sollte. Ich bekomme auch den gleichen Fehler, wenn ich() => {...} verwende (siehe mein Update). – devuxer

1

Schreiben Sie dies mit der Lambda-Syntax um.

var vf2 = foos.Join(bars, f => f.id, b => b.id, (foo, bar) => { foo.MissingProp = bar.MissingProp; return foo; }); 

Wenn Sie eine Erklärung dieser Syntax benötigen, lassen Sie es mich wissen.

+0

Aus irgendeinem Grund verursacht dies einen Fehler mit der Join-Klausel (obwohl ich die Join-Klausel nicht geändert habe): * Der Typ eines der Ausdrücke in der Join-Klausel ist falsch. Type -Inferenz fehlgeschlagen beim Aufruf von 'Join'. * – devuxer

+0

Das ist, weil wenn Sie auswählen, Sie sagen, welcher Typ zurückgegeben werden soll, setzt select() voraus, dass Sie einen Delegattyp zurückgeben. Ich denke, du solltest bei deiner Methode bleiben. –

+0

Hmm ... vielleicht kann es einfach nicht gemacht werden. Aber warum kann man den Rückgabetyp nicht von 'return f;' ableiten? Es weiß, dass f ein 'Foo' ist. – devuxer

5

denke ich icambron richtig ist, IMHO, desto besser lesbare Version ist dies:

var fooBar = from 
       f in foos 
       join 
       b in bars 
       on f.BarId equals b.Id 
       select new {f,b}; 

    foreach(var x in fooBar) 
     x.f.MissingProp = x.b.MissingProp; 

    // EDIT due to comments: add this if you 
    // need IEnumerable<Foo> returned 
    return fooBar.Select(fb => fb.f); 

Die from join select-Anweisungen für Abfragen werden, sollten sie nicht zum Mutieren des Inhalts einer Sequenz missbraucht werden.

EDIT: Hier ist eine weitere link bietet einige Einblicke, warum eine funktionale Form von ForEach ist keine gute Idee.

+0

Danke +1. Ich hatte darüber nachgedacht, 'foreach' zu benutzen, aber ich denke, ich habe versucht, zu ausgefallen zu sein :) Das ist eine gute Lösung. – devuxer

+0

Hoppla, ein Problem. Das lässt mich mit einem 'IEnumerable ' aber ich brauche ein 'IEnumerable '. Ich denke, wenn Sie 'fooBar.Select (fb => fb.f);' zu Ihrer Antwort hinzufügen, wird es korrekt sein. – devuxer

+2

Sie sollten auch in der Lage sein, 'var foobar = (....) zu machen. ForEach (....); 'und eine Zeile es! –

1

Wenn der Compiler nicht in der Lage ist, den korrekten Typ zu ermitteln, der an ein Lambda übergeben werden soll, können Sie den Typ natürlich selbst angeben.

sollte das hervorragend funktionieren:

select 
    (Foo f2, b) => { f2.MissingProp = b.MissingProp; return f2; } 

Beachten Sie, dass, wie Sie schon bemerkt haben, können Sie nicht f und hoffen, wiederverwenden können, dass sie ihre Bedeutung behalten.Dies ist eine neue Methodensignatur mit neuen Parametern, daher müssen Sie einen eindeutigen Namen dafür verwenden.

Wenn Sie dies tun, stellen Sie fest, dass der Compiler nicht in der Lage ist, selbst herauszufinden, welcher Typ das erste Argument sein sollte, aber Sie können es wie oben angeben.

+0

Was den unvollständigen Code betrifft, habe ich meine Rückmeldung vergessen. Habe es einfach repariert. – devuxer

+0

Sie haben auch das Ende-Semikolon nach der Linq-Abfrage verpasst. Sie sollten immer versuchen, das, was Sie in Ihrem Code haben, zu kopieren und einzufügen, nicht versuchen, es zu vereinfachen. Sie würden erstaunt sein, was die Leute hier vom Code lesen können :) –

+0

hat den letzten Teil der Antwort entfernt, um die bearbeitete Frage zu reflektieren. –

Verwandte Themen