Verwirrt über die Weitergabe Ausdruck vs. Func-Argumente
Ich habe einige Schwierigkeiten zu verstehen, die Unterschiede zwischen dem, wie Ausdrücke und Funcs funktionieren.
Dieses problem stellte sich, wenn jemand verändert eine Methode Signatur:
public static List<Thing> ThingList(Func<Thing, bool> aWhere)
Zu
public static List<Thing> ThingList(Expression<Func<Thing, bool>> aWhere)
Die brach meine Berufung code. Die alte aufrufen von code (was auch geklappt hat) sah so aus:
...
object y = new object();
Func<Thing, bool> whereFunc = (p) => p == y;
things = ThingManager.ThingList(whereFunc);
Den neuen code (der nicht funktioniert) sieht so aus:
...
object x = new object();
Expression<Func<Thing, bool>> whereExpr = (p) => p == x;
things = ThingManager.ThingList(whereExpr);
Diese ausfällt, innen ThingList(...) auf der Linie unter Verwendung des Ausdrucks:
var query = (from t in context.Things.Where(aWhere)
...
Mit dem runtime error:
Unable to create a constant value of type 'System.Object'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
Diesem Beispiel ist konstruiert, aber meine Vermutung ist, es hat etwas zu tun mit der lokalen Objekt-variable x nicht richtig "kopiert" in den Ausdruck.
Kann mir jemand erklären, wie man mit dieser situation umzugehen im Allgemeinen, und warum die Func
funktioniert, aber der Expression
nicht?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Den Grund für den Wechsel fast sicher war, "push" die Auswertung der Prädikat in der zugrundeliegenden store sichert Ihr
context
. Stattdessen bringen alleThings
in den Speicher und dann mitFunc<Thing,bool>
zu entscheiden, welche zu halten, der Autor der geänderten API entschiedenIQueryable
, und benötigt einExpression<Func<Thing,bool>>
für, die.Sind Sie richtig auf den Ursprung des Fehlers: im Gegensatz zu in-memory-Prädikate,
IQueryable
nicht verwenden Objekte, die es nicht wissen, z.B. die beliebige Instanzen vonobject
.Was Sie tun müssen, ist, um den Ausdruck zu ändern, um zu vermeiden, verweisen auf Objekte des Datentypen nicht unterstützt durch das Ziel-data-store (ich nehme an, der Ausdruck, die schließlich macht seinen Weg in ein Entity Framework oder Linq2Sql-Kontext). Zum Beispiel, anstatt zu sagen,
sollten Sie sagen,
(Ihre backing-store fast versteht sicherlich, dass ganze zahlen)
Den Unterschied zwischen Ausdruck und Func ist besser beschrieben in den Antworten hier: Unterschied zwischen Ausdruck<U<>> U<>
Einen schnellen workaround, um diese wieder funktionieren würde, der zum kompilieren der Ausdruck wieder in eine Func.