2009-11-26 5 views
16

Mir wurde gesagt, Reflection.Emit statt PropertyInfo.GetValue/SetValue zu verwenden, weil es auf diese Weise schneller ist. Aber ich weiß nicht wirklich, welche Sachen von Reflection.Emit und wie man es verwendet, um GetValue und SetValue zu ersetzen. Kann mir jemand dabei helfen?Reflection.Emit besser als GetValue & SetValue: S

+2

Huh? Mit Reflection.Emit können Sie Code zur späteren Ausführung erstellen. Aber es ist auch komplexer und fehleranfällig, ganz zu schweigen von schwer zu debuggen.Sie müssen beschreiben, was Sie mit GetValue/SetValue und mit welchen Leistungsanforderungen zu tun versuchen. Warum verwenden Sie Reflection überhaupt? –

+1

Ich vermute, er hat einige dynamisch geladene Objekte und möchte auf die Eigenschaft zugreifen, und die Frage ist, ob das Aufrufen von GetValue/SetValue oder * das Generieren von IL-Code zum Zugriff auf die Eigenschaft "hard-coded" * die bessere Sache wäre. Ich würde vorschlagen, mit Reflection.Emit.DynamicMethod zu versuchen und dann einfach zu überprüfen, welche schneller ist. Für mich war GetValue/SetValue ausreichend, ich musste nur IL-Code für die Behandlung von Ereignissen mit Signaturen erzeugen, die zur Kompilierzeit unbekannt sind. – OregonGhost

+0

I Benutzerreflexion zum Abrufen und Setzen von Werten auf Eigenschaften von Objekten (Ich kenne den Typ nicht der Objekte) – Omu

Antwort

26

Nur eine alternative Antwort; Wenn Sie die Leistung wollen, aber eine ähnliche API - in Betracht ziehen HyperDescriptor; diese verwendet Reflection.Emit unter (so dass Sie nicht haben), sondern setzt sich auf der PropertyDescriptor API, so dass Sie nur verwenden können:

PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj); 
props["Name"].SetValue(obj, "Fred"); 
DateTime dob = (DateTime)props["DateOfBirth"].GetValue(obj); 

eine Zeile Code, es zu ermöglichen, und es kümmert sich um alle das Caching usw.

+0

Was meinst du mit "HyperDescriptor für den Download verwenden "? Ich brauche nur Eigenschaften zu erhalten, und setze Werte auf sie, das ist alles – Omu

+0

Ich meine, Sie müssen die HyperDescriptor-Komponente von Codeprojekt herunterladen und aktivieren Sie es wie auf der Seite (auf verschiedene Arten) gezeigt. * Ohne * HyperDescriptor ist dies eine verherrlichte Reflexion; HyperDescriptor fängt TypeDescriptor ab und ersetzt den Reflection-Code durch dynamisches IL. –

+1

Es ist verwirrend, stimme ich zu; der gleiche Code funktioniert gut mit/ohne HyperDescriptor, aber es ist/viel/(~ 100x) langsamer ohne. Irgendwelche Probleme, die es funktionieren lassen, lassen Sie mich wissen (es war vor einigen Jahren, als ich es schrieb, aber ich erinnere mich noch an das meiste davon!) –

1

Der Zweck von Reflection.Emit unterscheidet sich vollständig von dem von PropertyInfo.Get/SetValue. Über Reflection.Emit können Sie IL-Code direkt ausgeben, zum Beispiel in dynamisch kompilierte Assemblies, und diesen Code ausführen. Natürlich könnte dieser Code auf Ihre Eigenschaften zugreifen.

Ich bezweifle ernsthaft, dass dies viel schneller als die Verwendung von PropertyInfo am Ende ist, und es ist auch nicht für diesen Zweck gemacht. Sie könnten beispielsweise Reflection.Emit als Codegenerator für einen kleinen Compiler verwenden.

1

Verwendung von Reflection.Emit scheint ein wenig zu "clever", sowie eine vorzeitige Optimierung. Wenn Sie Ihre Anwendung profilieren, und Sie feststellen, dass die GetValue/SetValue Reflexion der Engpass ist, dann könnte man bedenkt, Optimierung, aber wahrscheinlich nicht einmal dann ...

11

Verwenden PropertyInfo.GetValue/SetValue

Wenn Sie Performance-Probleme Cache das Propertyinfo-Objekt (GetProperty nicht wiederholt nennt)

wenn - und nur wenn - die Verwendung von Reflexion ist die Performance-Engpass Ihrer Anwendung (wie in einem Profiler zu sehen) verwenden Delegate.CreateDelegate

Wenn - und wirklich wirklich nur wenn - du absolut sicher bist, dass t lesen/schreiben Die Werte sind immer noch der größte Engpass. Es ist an der Zeit, etwas über die unterhaltsame Welt der Generierung von IL in Runtime zu lernen.

Ich bezweifle wirklich, dass es sich lohnt, jeder dieser Ebenen erhöht die Komplexität des Codes mehr als sie die Leistung verbessern - tun Sie nur, wenn Sie müssen.

Und wenn der Laufzeitzugriff auf Eigenschaften Ihr Leistungsengpass ist, ist es wahrscheinlich besser für den Kompilierzeit-Zugriff (es ist schwer, gleichzeitig generische und super hohe Leistung zu sein).

+0

Aber machbar: http: // www. codeproject.com/KB/cs/HyperPropertyDescriptor.aspx –

22

Wenn Sie dieselbe Eigenschaft mehrmals abrufen/einstellen, ist die Verwendung einer Komponente zum Erstellen einer typsicheren Methode in der Tat schneller als die Reflexion. Allerdings würde ich vorschlagen, Delegate.CreateDelegate anstelle von Reflection.Emit zu verwenden. Es ist einfacher, richtig zu kommen, und es ist immer noch unglaublich schnell.

Ich habe dies in meiner Protokollpuffer-Implementierung verwendet und es machte einen großen Unterschied vs PropertyInfo.GetValue/SetValue. Wie andere gesagt haben, tun Sie dies nur, nachdem Sie bewiesen haben, dass der einfachste Weg zu langsam ist.

Ich habe eine blog post mit mehr Details, wenn Sie sich entscheiden, die Route gehen.

+0

Sehr interessant - ich habe versucht, einen Delegaten zu FieldInfo.SetValue zu erstellen, und es hat absolut nichts geändert. Ziemlich offensichtlich, denn ich habe nur die Art geändert, wie die Funktion aufgerufen wird, und die Funktion selbst ist langsam. Wie haben Sie diese Leistungssteigerung erreicht? Ich hatte kein Glück, Informationen darüber in Ihrem Blogpost zu finden (vielleicht bin ich nur blind :-D) – Steffen

+0

Lesen Sie einfach Ihren Blogeintrag und entdeckte den GetGetMethod- und GetSetMethod-Teil, anscheinend war ich * blind vorher. Das erklärt natürlich natürlich den Geschwindigkeitsunterschied, aber für FieldInfos bin ich noch im Dunkeln: -S Ich freu mich aber auf Marcs Beispiel :-) Ich wollte euch nur wissen lassen, dass ich herausgefunden habe, was du gemacht hast um die Dinge durch Delegierte zu beschleunigen. – Steffen

+1

Cheers (+1) - Ich habe gerade diese Idee verwendet, um .1s - .8s pro Seite auf einigen gespiegelten Klassen zu speichern :-) – Keith