Was ist der einfachste Weg, um gegen eine Eigenschaft in C # zu codieren, wenn ich den Eigenschaftsnamen als Zeichenfolge habe? Zum Beispiel möchte ich dem Benutzer erlauben, einige Suchergebnisse nach einer Eigenschaft seiner Wahl (unter Verwendung von LINQ) zu ordnen. Sie wählen die Eigenschaft "order by" in der Benutzeroberfläche - natürlich als Zeichenfolgenwert. Gibt es eine Möglichkeit, diese Zeichenfolge direkt als Eigenschaft der linq-Abfrage zu verwenden, ohne bedingte Logik (if / else, switch) verwenden zu müssen, um die Zeichenfolgen Eigenschaften zuzuordnen. Reflexion?
Logischerweise möchte ich Folgendes tun:
query = query.OrderBy(x => x."ProductId");
Update: Ich habe ursprünglich nicht angegeben, dass ich Linq to Entities verwende - es scheint, dass Reflection (zumindest der GetProperty-, GetValue-Ansatz) nicht in L2E übersetzt wird.
quelle
Antworten:
Ich würde diese Alternative zu dem anbieten, was alle anderen gepostet haben.
Dies vermeidet wiederholte Aufrufe der Reflection-API zum Abrufen der Eigenschaft. Jetzt wird nur noch der Wert wiederholt.
jedoch
Ich würde die Verwendung von a
PropertyDescriptor
empfehlen, da diesTypeDescriptor
die Zuweisung von benutzerdefinierten s zu Ihrem Typ ermöglicht, wodurch einfache Operationen zum Abrufen von Eigenschaften und Werten möglich sind. Wenn kein benutzerdefinierter Deskriptor vorhanden ist, wird er ohnehin auf die Reflexion zurückgreifen.HyperDescriptor
Schauen Sie sich Marc Gravels Projekt auf CodeProject an, um es zu beschleunigen. Ich habe dies mit großem Erfolg verwendet; Es ist ein Lebensretter für leistungsstarke Datenbindung und dynamische Eigenschaftsoperationen für Geschäftsobjekte.quelle
PropertyDescriptor
sowieso eine sein (um benutzerdefinierte Typdeskriptoren zu berücksichtigen, die das Abrufen von Werten zu einer einfachen Operation machen könnten ).Ich bin etwas spät zur Party, aber ich hoffe, das kann hilfreich sein.
Das Problem bei der Verwendung von Reflection besteht darin, dass der resultierende Ausdrucksbaum mit ziemlicher Sicherheit von keinem anderen Linq-Anbieter als dem internen .NET-Anbieter unterstützt wird. Dies ist für interne Sammlungen in Ordnung, funktioniert jedoch nicht, wenn die Sortierung vor der Paginierung an der Quelle (z. B. SQL, MongoDb usw.) erfolgen soll.
Das folgende Codebeispiel enthält IQueryable-Erweiterungsmethoden für OrderBy und OrderByDescending und kann wie folgt verwendet werden:
Verlängerungsmethode:
Grüße, Mark.
quelle
Expression.Convert
konvertierenproperty
zuobject
? Ich erhalte eineUnable to cast the type 'System.String' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.
Fehlermeldung und das Entfernen scheint zu funktionieren.var propAsObject = Expression.Convert(property, typeof(object));
und nurproperty
anstelle vonpropAsObject
LINQ to Entities only supports casting EDM primitive or enumeration types
Ich mochte die Antwort von @Mark Powell , aber wie @ShuberFu sagte, gibt es den Fehler
LINQ to Entities only supports casting EDM primitive or enumeration types
.Das Entfernen
var propAsObject = Expression.Convert(property, typeof(object));
funktionierte nicht mit Eigenschaften, bei denen es sich um Werttypen handelte, wie z. B. Ganzzahl, da das int-Objekt nicht implizit eingerahmt wurde.Unter Verwendung von Ideen von Kristofer Andersson und Marc Gravell habe ich einen Weg gefunden, die abfragbare Funktion unter Verwendung des Eigenschaftsnamens zu erstellen und sie weiterhin mit Entity Framework funktionieren zu lassen. Ich habe auch einen optionalen IComparer-Parameter eingefügt. Achtung: Der IComparer-Parameter funktioniert nicht mit Entity Framework und sollte bei Verwendung von Linq to Sql weggelassen werden.
Folgendes funktioniert mit Entity Framework und Linq to Sql:
Und @Simon Scheurer das funktioniert auch:
Und wenn Sie Entity Framework oder Linq to Sql nicht verwenden, funktioniert dies:
Hier ist der Code:
quelle
Aggregate
Fragment ist großartig! Es kümmert sich um virtuelle Ansichten, die aus dem EF Core-Modell mit erstellt wurdenJoin
, da ich Eigenschaften wie "T.Property" verwende. AndernfallsJoin
wäre eine Bestellung nachInvalidOperationException
oder entweder nicht möglichNullReferenceException
. Und ich muss NACH bestellenJoin
, da die meisten Abfragen konstant sind, die Bestellungen in Ansichten nicht.Aggregate
Fragment wirklich nicht genug würdigen. Ich glaube, es war eine Kombination aus Marc Gravells Code und einer Intellisense-Empfehlung. :)products.OrderBy(x => x.ProductId)
könnten Sie verwendenproducts.OrderBy("ProductId")
Ja, ich glaube nicht, dass es einen anderen Weg als Reflection gibt.
Beispiel:
quelle
Ich habe versucht, die genaue Syntax auf den Kopf zu stellen, aber ich denke, das ist richtig.
quelle
Reflexion ist die Antwort!
Es gibt viele Dinge, die Sie tun können, um die reflektierten PropertyInfo zwischenzuspeichern, nach fehlerhaften Zeichenfolgen zu suchen, Ihre Abfragevergleichsfunktion zu schreiben usw., aber im Kern tun Sie dies.
quelle
Sie können dynamisches Linq verwenden - lesen Sie diesen Blog.
Schauen Sie sich auch diesen StackOverFlow-Beitrag an ...
quelle
Produktiver als Reflexionserweiterung auf dynamische Auftragspositionen:
Beispiel:
Möglicherweise müssen Sie auch konforme Lambas zwischenspeichern (z. B. im Wörterbuch <>).
quelle
Auch dynamische Ausdrücke können dieses Problem lösen. Sie können stringbasierte Abfragen über LINQ-Ausdrücke verwenden, die zur Laufzeit möglicherweise dynamisch erstellt wurden.
quelle
Ich denke, wir können einen leistungsstarken Werkzeugnamen Ausdruck verwenden und in diesem Fall wie folgt als Erweiterungsmethode verwenden:
quelle