Verwenden des LINQ-Ausdrucks zum Zuweisen der Eigenschaft eines Objekts

8

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?

    
Stevoman 28.11.2011, 21:34
quelle

3 Antworten

15

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):

%Vor%

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:

%Vor%     
Bryan Watts 28.11.2011, 22:58
quelle
3

Was Sie tun könnten, ist, den Eigenschaftsnamen aus einem linq Ausdruck des Typs p => p.Id zu extrahieren, indem Sie so etwas verwenden

%Vor%

.. 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)

    
Juri 28.11.2011 21:45
quelle
0

Dies scheint eine perfekte Übereinstimmung für dynamic zu sein. Sie können eine dynamische Klasse mit den Eigenschaften basierend auf den Schlüsseln im Wörterbuch erstellen. Überprüfen Sie die Klasse DynamicObject .

    
zmbq 28.11.2011 22:03
quelle

Tags und Links