Nehmen wir an, ich habe die folgende Klasse:
%Vor%Basierend auf diesen Informationen ist mein Ziel, einen Lambda-Ausdruck wie folgt zu erstellen:
%Vor% lang
und name
sind lokale Variablen, die ich beim Erstellen des Ausdrucks als konstante Werte hinzufügen möchte.
Wie Sie sehen, ist die kompilierte Funktion vom Typ Func<Genre, bool>
Um Ihnen das zu verdeutlichen, möchte ich etwas Ähnliches erreichen:
%Vor%Ich bin mir der Existenz von Ausdrucksbäumen bewusst, aber ich bin ziemlich neu in diesem Thema, daher weiß ich nicht einmal, wie ich anfangen soll.
Kann dieses Problem gelöst werden? Wie kann ich einen solchen Ausdruck dynamisch erstellen?
Sie können Schnittstellen verwenden, um einen Func für die Schnittstelle zu erstellen, der die erforderlichen Eigenschaften definiert hat.
Beispiel:
%Vor%Eine alternative Implementierung dieses Konzepts kann erreicht werden, indem eine GetLanguage- und GetName-Methode auf Ihrer Schnittstelle bereitgestellt wird. Dies würde die Abonnenten zwingen, die zugrunde liegenden Methoden zu implementieren, um eine "Sprache" und einen Namen basierend auf ihren eigenen internen Methoden zurückzugeben .
%Vor% Bearbeiten Sie von Ihrem Kommentar oben: @kaveman I only have the key values, but I can fetch the key properties via reflection using some custom attributes that I defined. In this example, Language and Name would be decorated with an attribute that defines them as key properties
Meine Antwort ist, diesen Gedanken vollständig zu vermeiden. Erstellen Sie eine Schnittstelle, die die Methoden definiert, die Sie zum Ausführen des gesuchten Ausdrucks benötigen, und lassen Sie die Entitäten davon erben. Sie könnten Ihre Methoden auf der Schnittstelle "GetKeyOne" und "GetKeyTwo" haben. Dann muss Ihr Ausdruck nicht dynamisch sein, Sie müssen lediglich definieren, was der Ausdruck macht, wenn er mit KeyOne und KeyTwo interagiert, die in jedem Implementierer definiert sind.
Angenommen, Sie haben Attribute für jede der Eigenschaften der Entitäten, mit denen Sie sich hier befassen möchten (siehe Kommentare ), und Sie haben den Typ Parameter (nennen Sie T
) eine mögliche Signatur für CreateExpression
ist:
Auf diese Weise funktioniert Ihr CreateExpression
mit dem bekannten generischen Typ, und der Aufrufer kann angeben, welche Tests für die Eigenschaften des Elements durchgeführt werden sollen. Hier nehmen wir an, dass key
der Name der Eigenschaft ist, an dem das Objekt reflektiert werden soll (stellen Sie sicher, dass es das bekannte Attribut hat), während value
der erforderliche Wert dieser Eigenschaft ist. IOrderedDictionary
ist eine Möglichkeit, den Kurzschluss der &&
Tests zu erzwingen, wenn das dein Ding ist.
Sie können zusätzliche Einschränkungen für T
(z. B. T
muss eine Schnittstelle implementieren) über generisch hinzufügen Geben Sie Beschränkungen mit where
Siehe auch Überprüfen Sie, ob die Eigenschaft ein Attribut aufweist
Und Reflection - Erhalte Attributnamen und Wert für die Eigenschaft
Dies wird es tun und sollte es ziemlich benutzerfreundlich machen,
zu bauen %Vor%Dann benutzt du es so:
%Vor%Beachten Sie, dass die Variablen mit den Eigenschaftsnamen übereinstimmen müssen. Andernfalls benötigen Sie eine Art von Zuordnung [lang = & gt; Sprache] usw.
Um es auszuwerten:
%Vor%Oder Sie können es zum Beispiel an EF übergeben:
%Vor%