Warum würden Sie Expression & lt; Func & lt; T & gt; & gt; anstatt Func & lt; T & gt;
Ich verstehen, lambdas und die Func
und Action
Delegierten. Aber Ausdrücke stump mir. Unter welchen Umständen würden Sie eine Expression<Func<T>>
eher als ein plain old Func<T>
?
InformationsquelleAutor der Frage Richard Nagle | 2009-04-27
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn Sie möchten, zur Behandlung von lambda-Ausdrücken als Ausdruck Bäume und von innen anschauen, anstatt Sie ausführt. Zum Beispiel, LINQ to SQL, bekommt den Ausdruck und konvertiert Sie in die entsprechende SQL-Anweisung und sendet es an server (anstatt auf die Ausführung der lambda).
Konzeptionell
Expression<Func<T>>
ist völlig anders vonFunc<T>
.Func<T>
bezeichnet einedelegate
was ziemlich viel ist, einen Zeiger auf eine Methode undExpression<Func<T>>
bezeichnet eine Baumstruktur für einen lambda-Ausdruck. Diese Baumstruktur beschreibt, was ein lambda-Ausdruck hat eher als die eigentliche Sache. Es ist im Grunde hält Daten über die Zusammensetzung von Ausdrücken, Variablen, Methodenaufrufe, ... (zum Beispiel hält er Informationen wie diese lambda-Ausdruck Konstanten + ein paar parameter). Diese Beschreibung können Sie es konvertieren, um eine tatsächliche Methode (mitExpression.Compile
) oder andere Sachen (wie die LINQ to SQL-Beispiel). Der Akt der Behandlung von Lambda-Ausdrücke anonyme Methoden und expression trees ist eine Reine compile-Zeit-Sache.effektiv kompilieren, um eine IL-Methode, bekommt nichts und gibt 10.
umgewandelt werden, um eine Datenstruktur, die beschreibt, ein Ausdruck, der bekommt keine Parameter und gibt den Wert 10:
Während Sie beide die gleiche zur compile-Zeit, was der compiler generiert, wird völlig anders.
InformationsquelleAutor der Antwort Mehrdad Afshari
Ich bin das hinzufügen einer Antwort-für-noobs, weil diese Antworten schien über meinem Kopf, bis ich erkannte, wie einfach es ist. Manchmal ist es Ihre Erwartung, dass es kompliziert ist, macht Sie nicht 'Ihren Kopf herum wickeln'.
Habe ich nicht brauchen, um den Unterschied zu verstehen, bis ich ging in eine wirklich lästige " bug " zu benutzen versuchen, LINQ-to-SQL-allgemein:
Diese hat Super funktioniert, bis ich anfing, OutofMemoryExceptions auf größere Datenmengen. Das setzen von breakpoints innerhalb der lambda-Ausdruck machte mir klar, dass es war, Durchlaufen jede Zeile in meine Tabelle ein-by-one auf der Suche nach übereinstimmungen zu meinem lambda-Zustand. Das überfragt mich für eine Weile, denn warum zum Teufel ist es die Behandlung meiner Daten-Tabelle als eine riesige IEnumerable statt das zu tun, LINQ-to-SQL, wie es soll? Es war auch genau das gleiche in meiner LINQ-to-MongoDb-Pendant.
Das Update war einfach zu drehen
Func<T, bool>
inExpression<Func<T, bool>>
so habe ich gegoogelt warum braucht es eineExpression
stattFunc
sind, landen hier.Ein Ausdruck, der dreht einfach einen Delegaten in einer Daten über sich selbst. So
a => a + 1
wird so etwas wie "Auf der linken Seite gibt es eineint a
. Auf der rechten Seite fügen Sie 1." Das ist es. Sie können jetzt nach Hause gehen. Es ist offensichtlich mehr strukturiert als das, aber das ist im Grunde alles ein Ausdruck Baum wirklich ist-nichts um Ihren Kopf herum wickeln.Verständnis, dass, es wird klar, warum LINQ-to-SQL benötigt eine
Expression
und einFunc
ist nicht ausreichend.Func
nicht tragen mit ihm ein Weg, um sich in sich selbst, um zu sehen, die nitty-gritty, wie übersetzen Sie es in eine SQL-MongoDb/andere Abfrage. Sie können nicht sehen, ob es tut addition oder Multiplikation auf Subtraktion. Alles, was Sie tun können, ist laufen.Expression
auf der anderen Seite, können Sie innerhalb des Delegaten und alles sehen, es tun zu wollen, die Sie dazu befähigen, um es zu übersetzen in das, was Sie wollen, wie eine SQL-Abfrage.Func
hat nicht funktioniert, weil mein DbContext war blind für das, was war eigentlich in den lambda-Ausdruck in SQL, so Tat es die nächste beste Sache, und bekräftigte, dass bedingte durch jede Zeile in meiner Tabelle.Edit: Darlegung auf meinen letzten Satz an John Peter Wunsch:
IQueryable erweitert IEnumerable, also IEnumerable Methoden wie
Where()
erhalten überladungen, akzeptierenExpression
. Wenn Sie übergeben einExpression
Sie halten ein IQueryable als Ergebnis, aber wenn Sie passieren einenFunc
Sie fallen wieder zurück auf die base IEnumerable und Sie erhalten eine IEnumerable als Ergebnis. In anderen Worten, ohne zu bemerken, Sie haben sich dem dataset in eine Liste zu iterieren, als Gegensatz zu etwas Abfragen. Es ist schwer, einen Unterschied bemerken, bis Sie wirklich mal unter die Haube schauen auf die Signaturen.InformationsquelleAutor der Antwort Chad Hedgcock
Ein extrem wichtiger Aspekt in der Wahl des Ausdrucks vs Func ist, dass das IQueryable-Anbieter wie LINQ to Entities 'verdauen', was Sie übergeben ein Ausdruck, aber ignorieren, was Sie übergeben ein Func. Ich habe zwei blog-Beiträge zum Thema:
Mehr auf Ausdruck vs Func mit Entity Framework und
Falling in Love mit LINQ - Teil 7: Begriffe und Funcs (der Letzte Abschnitt)
InformationsquelleAutor der Antwort LSpencer777
Ich möchte noch hinzufügen, einige Notizen über die Unterschiede zwischen
Func<T>
undExpression<Func<T>>
:Func<T>
ist nur ein normaler old-school-MulticastDelegate;Expression<Func<T>>
ist eine Repräsentation der lambda-Ausdruck in form von Meinungsäußerung Baum;Func<T>
;ExpressionVisitor
;Func<T>
;Expression<Func<T>>
.Gibt es einen Artikel, der beschreibt die details mit code-Beispiele:
LINQ: Func<T> vs. Ausdruck<U<T>>.
Hoffe, es wird hilfreich sein.
InformationsquelleAutor der Antwort Olexander
Gibt es eine mehr philosophische Erklärung von Krzysztof Cwalina Buch(Framework Design Guidelines: Konventionen, Ausdrücke und Muster für Wiederverwendbare .NET-Bibliotheken);
Bearbeiten für nicht-Bild-version:
InformationsquelleAutor der Antwort Oguzhan Soykan
LINQ ist das kanonische Beispiel (zum Beispiel, im Gespräch mit einer Datenbank), aber in Wahrheit, jede Zeit, die Sie kümmern sich mehr um Ausdruck was zu tun, anstatt es tatsächlich zu tun. Zum Beispiel habe ich diesen Ansatz in der RPC-stack von protobuf-net (um zu vermeiden, code-Erzeugung etc.), so wird Sie eine Methode aufrufen mit:
Diese dekonstruiert die expression tree zu beheben
SomeMethod
(und der Wert jedes argument), führt der RPC-Aufruf, aktualisiertref
/out
args, und gibt das Ergebnis aus der remote-call. Dies ist nur möglich durch die expression tree. Decke ich diese mehr hier.Weiteres Beispiel ist, wenn Sie den Aufbau der Ausdruck Bäume manuell für die Zwecke der Erstellung, um einen lambda-Ausdruck, wie durch die generische Operatoren code.
InformationsquelleAutor der Antwort Marc Gravell
Würden Sie einen Ausdruck verwenden, wenn Sie möchten, gönnen Sie Ihrer Funktion als Daten und nicht als code. Sie können dies tun, wenn Sie wollen, zu manipulieren, den code (als Daten). Die meisten der Zeit, wenn Sie nicht sehen, eine Notwendigkeit Ausdrücken, dann haben Sie wahrscheinlich nicht brauchen, um es zu nutzen.
InformationsquelleAutor der Antwort Andrew Hare
Der primäre Grund ist, wenn Sie nicht möchten, führen Sie den code direkt, sondern, wollen, um zu überprüfen es. Dies kann für eine beliebige Anzahl von Gründen:
InformationsquelleAutor der Antwort Luaan
Sehe ich keine Antworten, noch die erwähnen, Leistung. Vorbei
Func<>
s inWhere()
oderCount()
schlecht ist. Echt schlimm. Wenn Sie eineFunc<>
dann ruft es dieIEnumerable
LINQ-Sachen stattIQueryable
was bedeutet, dass die ganzen Tabellen gezogen bekommen und dann gefiltert.Expression<Func<>>
ist deutlich schneller, vor allem, wenn Sie die Abfrage einer Datenbank, die Leben von einem anderen server.InformationsquelleAutor der Antwort mhenry1384