Ich arbeite also mit einem alten Datenmodell, und ich muss irgendwie in dem arbeiten, was ich bekommen habe.
Wenn ich eine Datenbankabfrage durchführe, gibt das Modell Daten als
zurück %Vor%Wo für jedes Wörterbuch der Schlüssel der Spaltenname und der Wert der Spaltenwert ist. Wie Sie sich vorstellen können, ist die Arbeit damit ein Alptraum von foreach loops und type casting
Ich hoffe, einige POCO-Viewmodels zu definieren und dann etwas zu erstellen, das LINQ / Reflection und eine "Zuweisungs-Bindungs-Map" verwendet, um von einem scheußlichen Rückgabewert zu meinem schönen, sauberen POCO zu gelangen. So könnte ich "Maps" mit den Spaltennamen und Lambdas zu den Eigenschaften auf meinem POCO definieren, ähnlich wie diese ...
%Vor%Dann konvertiere so ...
%Vor%Kann dies mit einer Art von Reflexion getan werden, und wenn ja, wie?
Hier ist ein Ansatz, der Ausdrucksbäume verwendet. Definieren Sie zuerst die API der Karte:
%Vor%Sie würden es so verwenden:
%Vor%Um es zu implementieren, würden Sie zunächst ein Wörterbuch definieren, um Namen aus der Datenquelle den Eigenschaften zuzuordnen:
%Vor% Als nächstes würden Sie die Add
-Methode in Bezug auf dieses Wörterbuch implementieren (alle Fehlerbehandlung als Übung für den Leser):
Dann würden Sie eine Methode dynamisch kompilieren, indem Sie Ausdrucksbäume verwenden, die die Zuweisungen durchführt (es klingt erschreckender als es ist). Der einfachste Weg, diesen Prozess zu visualisieren, ist ein Beispiel dessen, was wir bauen. Was wir wollen, ist ein Code, der das tut:
%Vor%Aber das können wir wegen der dynamischen Mappings zur Kompilierzeit nicht wissen. Wir werden also eine Funktion erstellen, die genau diesen Code enthält, aber zur Laufzeit kompiliert wird. Ausdrucksbäume sind nur Laufzeitdaten, die denselben Code darstellen, den Sie zur Kompilierungszeit schreiben könnten.
Zunächst müssen wir eine Reihe von Bindungen (Zuweisungen) für die Eigenschaften erhalten:
%Vor% Was wir hier sagen, ist, dass Sie für jede Eigenschaft in den zugeordneten Eigenschaften den Wert nachschlagen und ihn zu einer Konstante machen (für Id
, dies könnte der Wert 7 sein) und binden Sie die entsprechende Eigenschaft an sie. Dies gibt uns den Ausdruck Id = 7
. Wir wiederholen dies für alle Eigenschaften und geben uns alle Aufgaben.
Sobald wir diese Bindungen haben, können wir die vollständige Elementinitialisierung erstellen, die den Konstruktoraufruf enthält:
%Vor% Da wir in der Klassendeklaration where T : new()
angegeben haben, ist garantiert, dass hier ein parameterloser Konstruktor aufgerufen wird. Wir übergeben die Eigenschaftsbindungen, die wir zuvor erstellt haben, und geben uns eine Datenstruktur, die den Initialisierungsausdruck darstellt, den wir erstellen wollten.
Was wissen wir also? Wir haben diese Datenstruktur, aber wie nennen wir den Code? Um dies zu tun, müssen wir diesen Ausdruck in eine Funktion einfügen, die wir aufrufen können, weil das einzige, was Sie tatsächlich aufrufen können , eine Methode ist. Das bedeutet, dass wir wirklich Code erstellen, der so aussieht:
%Vor%Das ist eine parameterlose Funktion, die, wenn sie aufgerufen wird, das initialisierte Objekt zurückgibt. Dies wird auch als Lambda-Ausdruck bezeichnet. Wir können die Datenstruktur dafür so bekommen:
%Vor% Wir erstellen einen Lambda-Ausdruck, dessen Body die Member-Initialisierung ist, was genau der Code ist, den wir oben geschrieben haben. Wir geben den Delegattyp Func<T>
an, weil er keine Parameter akzeptiert und ein Objekt des zugeordneten Typs zurückgibt.
Dann kompilieren wir es. Dieser Aufruf generiert eine Methode mit der Signatur Func<T>
, die wir aufrufen können und die den Code enthält, den wir als Datenstruktur erstellt haben. Dies ist eine nette Art, Reflektionen ohne direkte Reflektion zu machen.
Schließlich implementieren wir die CreateObject
-Methode, die wir zuvor definiert haben, indem wir die Funktion erstellen und aufrufen und uns eine Instanz von T
( ProductViewModel
hier) geben:
Was Sie tun könnten, ist, den Eigenschaftsnamen aus einem linq Ausdruck des Typs p => p.Id
zu extrahieren, indem Sie so etwas verwenden
.. und verwenden Sie dann die einfache alte Reflektion, um den Wert der Objektinstanz zuzuweisen. Erstellen Sie zum Beispiel eine Methode
%Vor%(hat den Code nicht kompiliert; für den Reflektionsteil gibt es zahlreiche Artikel im Web. Hoffe das hilft)
Tags und Links c# linq reflection