Folgen Sie den Beispielen auf diesen Beitrag und Follow-up Frage , ich versuche Feld-Getter / Setter mit kompilierten Ausdrücken zu erstellen.
Der Getter funktioniert einfach großartig, aber ich habe den Setzer fest im Griff, da ich den Setter brauche, um einen beliebigen Typ von Feldern zuzuordnen.
Hier mein Setter-Aktion Builder:
%Vor%Jetzt speichere ich die generischen Setter in einer Cache-Liste (weil der Setter natürlich jedes Mal ein Performance-Killer ist), wo ich sie als einfache "Objekte" eingreife:
%Vor%Jetzt versuche ich einen Feldwert wie folgt einzustellen:
%Vor%Ich könnte einfach eine generische Methode aufrufen und jedes Mal umwandeln, aber ich mache mir Sorgen um den Leistungsaufwand ... Irgendwelche Vorschläge?
- BEARBEITETE ANTWORT
Auf der Grundlage der Antwort von Herrn Anderson erstellte ich ein kleines Testprogramm, das den Wert, die zwischengespeicherte Reflektion (wo FieldInfo's zwischengespeichert werden, direkt setzt) vergleicht ) und der zwischengespeicherte Multi-Typ-Code. Ich verwende Objektvererbung mit bis zu 3 Vererbungsebenen ( ObjectC : ObjectB : ObjectA
).
Der vollständige Code des Beispiels finden Sie hier.
Eine einzelne Iteration des Tests ergibt folgende Ausgabe:
%Vor%Natürlich zeigt dies einfach die Kosten für die Erstellung der Objekte an - dies ermöglicht es uns, den Offset der Erstellung der zwischengespeicherten Versionen von Reflection und Expressions zu messen.
Lassen Sie uns als nächstes 1.000.000 Mal laufen:
%Vor% Der Vollständigkeit halber: Ich entfernte den Aufruf der "set" -Methode, um die Kosten für den Setter zu ermitteln ( FieldInfo
für die Reflektionsmethode, Action<object, object>
für den Ausdruck case). Hier die Ergebnisse:
HINWEIS: Der Zeitanstieg hier ist nicht darauf zurückzuführen, dass die Zugriffszeiten bei größeren Wörterbüchern langsamer sind (da sie Zugriffszeiten O(1)
haben), sondern aufgrund der Tatsache, dass die Anzahl der Zugriffe erhöht wird (4 Zeiten pro Iteration für ObjectA
, 8 für ObjectB
, 12 für ObjectC
) ... Wie man sieht, macht hier nur der Erstellungsoffset einen Unterschied (was zu erwarten ist).
Fazit: Wir haben die Leistung um den Faktor 2 oder mehr verbessert, aber wir sind immer noch weit von der Leistung des direkten Feldsets entfernt ... Das Auffinden des korrekten Setter in der Liste entspricht gut 10% der Zeit.
Ich werde es mit Expression Trees anstelle von Reflection versuchen. Geben Sie an, ob wir die Lücke weiter reduzieren können ... Jeder Kommentar ist mehr als willkommen.
BEARBEITEN 2 Ich fügte Ergebnisse hinzu, indem ich den Ansatz mit einer generischen "Accessor" -Klasse nutze, wie von Eli Arbel auf dieser Beitrag .
Wenn Sie Operationen für mehrere Typen unterstützen möchten, sollte Ihr Funktionscache durch Type
UND Feldname ( string
) indiziert werden, und die Funktionen sollten langsam erstellt werden. Versuchen Sie Folgendes:
Andernfalls, wenn Sie dies nur mit einem Typ machen müssen, wird Ihr Prozess:
%Vor%Tags und Links c# reflection expression-trees setter fieldinfo