Gibt es eine Möglichkeit zu schaffen, einen Delegierten zum abrufen und festlegen von Werten für ein FieldInfo?
Für Eigenschaften gibt es GetGetMethod
und GetSetMethod
so dass ich tun kann:
Getter = (Func<S, T>)Delegate.CreateDelegate(typeof(Func<S, T>),
propertyInfo.GetGetMethod());
und
Setter = (Action<S, T>)Delegate.CreateDelegate(typeof(Action<S, T>),
propertyInfo.GetSetMethod());
Aber wie gehe ich über die FieldInfo
s?
Ich bin nicht auf der Suche nach Delegierten zu GetValue
und SetValue
(was bedeutet, ich werde aufrufen Reflexion jedes mal)
Getter = s => (T)fieldInfo.GetValue(s);
Setter = (s, t) => (T)fieldInfo.SetValue(s, t);
aber wenn es ein CreateDelegate
Ansatz hier? Ich meine seit Zuweisungen einen Wert zurückgeben, kann ich behandeln Aufgaben wie eine Methode? Wenn ja, ist es ein MethodInfo
Griff für es? In anderen Worten wie gebe ich die Recht MethodInfo
einstellen und immer einen Wert von einem member Bereich zu CreateDelegate
Methode, so daß ich einen Delegat zurück, mit dem ich Lesen und schreiben kann-Felder direkt?
Getter = (Func<S, T>)Delegate.CreateDelegate(typeof(Func<S, T>), fieldInfo.??);
Setter = (Action<S, T>)Delegate.CreateDelegate(typeof(Action<S, T>), fieldInfo.??);
Ich kann Ausdruck erstellen und zu kompilieren, aber ich bin auf der Suche nach etwas einfacher. Am Ende habe ich nicht dagegen, geht der Ausdruck der route, wenn es keine Antwort für die gestellte Frage, wie unten gezeigt:
var instExp = Expression.Parameter(typeof(S));
var fieldExp = Expression.Field(instExp, fieldInfo);
Getter = Expression.Lambda<Func<S, T>>(fieldExp, instExp).Compile();
if (!fieldInfo.IsInitOnly)
{
var valueExp = Expression.Parameter(typeof(T));
Setter = Expression.Lambda<Action<S, T>>(Expression.Assign(fieldExp, valueExp), instExp, valueExp).Compile();
}
Oder bin ich nach der nicht vorhandenen (da habe ich nirgends gesehen, sowas noch) ?
- Gibt es irgendein Grund, warum Sie benötigen, um call
Delegate.CreateDelegate
? Sie haben bereits einen Delegierten mitgetter
. Einfach anrufengetter(myInstanceOfT)
ruft diefieldInfo.GetValue
Methode und kehren Sie den Wert. - ja die Leistung ist der Schlüssel. Siehe diesen thread: stackoverflow.com/questions/8087611/...
- Diese
Func<S, T> getter = s => (T)fieldInfo.GetValue(s);
alle, die Sie tun können, weil Feld nicht den setter\getter-Methode, wie es ist in einer Eigenschaft. Wenn die Leistung der Schlüssel ich empfehle den Ausdruck. - Ich weiß, ich muss schließlich Ausdruck verwenden, wenn ich nicht bestehen können, eine methodinfo für die Einstellung und Werte zu einem Feld. Einfach zu sehen, ob es simuliert werden kann.
- Sie wollen auch das delegieren von arbeiten für readonly-Felder und private Felder?
- readonly-Felder sollten nur lesbar sein. Für private Felder, ja (aber ich werde nur im privaten Rahmen - ich meine innerhalb der Klasse selbst). Im Grunde werde ich respektieren den Schutz/privacy/Sichtbarkeit
- Werfen Sie einen Blick auf meine Antwort. Sie können es ändern, wie auch immer Sie wollen, Präfekt readonly-Felder bleiben readonly oder Sie zwangsweise überschreiben. Mit diesen zwei kleinen Funktionen, die mich gerettet eine Menge Zeit.
- Ich sah schon auf Ihre Antwort, da es veröffentlicht wurde. Und wie gesagt, es ist nur etwas, was ich schon geschrieben in meiner Frage.
- Stimmt... Sie schon vorgeschlagen, in diese Richtung. Aber Sie bat um etwas so einfaches wie: '(Func<S, T>)zu Delegieren.CreateDelegate(typeof(Func<S, T>), fieldInfo.?);' Solche Funktionen, die nicht vorhanden ist! Ich habe nur vorgeschlagen, um zu schaffen, wie eine "einfache" Funktion selbst. Auf diese Weise verhindern Sie, dass Sie mit Ausdrücken, die überall im code, und Sie können einfach anrufen, die einfache Funktion, genau das, was Sie gefragt haben. Nun, wenn der KÖRPER von dieser Funktion kann einfacher sein, die Antwort ist einfach: NEIN! (mit der opion, dass IL ist nicht einfacher). Perhapse ich missverstehen Ihre Frage: willst du ein einfacher Anruf oder ein einfacher Körper?
- Ehrlich gesagt, ich war nach einer
get-set
Methode-pair-Mädchen für fieldinfo (ähnliche Eigenschaften) und überhaupt nicht nach einer Funktion mit dem NamenCreateDelegate
aber intern geht die expression route. Das war nicht der Zweck der Frage. Wenn Sie nahm es so, tut mir Leid. Ich akzeptiere kann ich nicht formulieren, dass die Frage so deutlich wie Sie wollte. Ich habe nicht gefragt, eine Frage nicht zu wissen, wie refactor-Methode und geben Sie ihm einen Namen. Sicherlich nicht um zu öffnen ein Kopfgeld für Sie. - Naja... in diesem Fall ist die Antwort einfach: Nein, es gibt Keine vorhandene (schnell) Get/Set-Methoden für ein Feld, nur der (langsame) GetValue/SetValue von FieldInfo.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Feld Zugang nicht erfolgt über eine Methode (wie get-und Set-Methoden) - es ist ausgeführt mit einer IL Instruktion-also gibt es nichts, was Sie zuweisen einer Stellvertretung. Sie müssen mit dem expression-route zu erstellen, die einen "block" der code (effektiv IL) zugewiesen werden können, eine Stellvertretung.
Als Peter Ritchie vorgeschlagen, können Sie kompilieren Ihren eigenen code zur Laufzeit. Die Methode kompiliert, sobald Sie rufen die Delegierten für die erste Zeit. Also der erste Anruf wird langsam sein, aber jedem nachfolgenden Aufruf wird so schnell wie Sie bekommen können in .NETTO ohne nicht verwalteten Zeiger/Gewerkschaften. Außer für den ersten Aufruf des Delegaten ist rund 500-mal schneller als FieldInfo direkt.
Beachten Sie, dass structs als Wert übergeben werden. Das bedeutet, dass ein
Action<S, T>
nicht verwendet werden können, ändern Sie die Mitglieder einer Struktur, wenn es übergeben wird der Wert als erstes argument.field.Module
parameter, wie folgt:var getMethod = new DynamicMethod(methodName, typeof(TMember), new[] { typeof(TObject) }, field.Module, true);
[2019 edit: Seit diesem post war schon immer einer meiner Favoriten, es ist bittersüß zu beachten, dass der Ansatz, den ich hier zeige, wurde vollständig abgelöst, in meine eigenen Projekte, durch eine neue, ganz andere und viel elegantere Technik, die ich ausführlich an diese Antwort].
Mithilfe der neuen " ref Rückkehr " - Funktion in C# 7.0 kann der Prozess der Erstellung und Verwendung von Laufzeit dynamisch generierte get/set-Accessoren viel einfacher und syntaktisch transparent. Statt DynamicMethod zu emittieren separate getter und setter Funktionen für den Zugriff auf das Feld können Sie nun eine einzige Methode gibt eine verwalteten Zeiger-Typ Referenz auf dem Gebiet, der im wesentlichen einem einzigen accessor, der (wiederum) ermöglicht die bequeme ad-hoc - bekommen und set Zugang. Unten Stelle ich eine helper utility-Funktion vereinfacht die Generierung einer ByRef getter-Funktion für beliebige (D. H. private) Instanz-Feld in jeder Klasse.
➜ Für "nur-code", überspringen Sie den Hinweis weiter unten.
Als ein Beispiel, sagen wir, wir möchten den Zugriff auf eine private Instanz-Feld
m_iPrivate
eineint
definiert in der KlasseOfInterestClass
:Weiter nehmen wir an, wir haben eine statische Feld "Referenz-getter" - Funktion, das dauert ein
OfInterestClass
Instanz und gibt den gewünschten Wert im Feld durch Verweis mit dem neuen C# 7 " ref Rückkehr " - Funktion (unten gebe ich code zu generieren solche Funktionen zur Laufzeit über DynamicMethod):Solche Funktion ("ref-getter," sagen wir mal) ist alles, was wir brauchen, um zu haben vollständigen lese - /Schreibzugriff Zugriff auf das private Feld. In den folgenden Beispielen beachten Sie insbesondere die setter-aufrufen Vorgang—und die Demonstrationen mit dem (z.B.)
++
und+=
Betreiber—da die Anwendung dieser Operatoren direkt auf eine Aufruf der Methode Blick ein wenig ungewöhnlich, wenn Sie nicht up-to-Geschwindigkeit auf C#7.Da ist der Punkt, jeder Betrieb in diesen Beispielen gezeigt, manipuliert
m_iPrivate
in situ (d.h., direkt innerhalb dessen die Instanzoic
), so dass alle und alle änderungen sind öffentlich sichtbar, es sofort. Es ist wichtig zu erkennen, dass dies bedeutet, dassprv
trotzint
-eingegeben und lokal deklariert, verhält sich nicht wie ein typischer "local" - Variablen. Dies ist besonders bedeutsam für die gleichzeitige code; nicht nur sind die änderungen sichtbar vorMyFunction
verlassen hat, aber jetzt mit C# 7, die Anrufer haben die Möglichkeit behalten eine ref return verwalteter Zeiger (als ref lokalen) und damit verändern Sie das Ziel für eine beliebig lange Zeit danach (wenn auch notwendigerweise verbleibenden unten der ref-Gewinnung stack frame, dass ist).Natürlich ein Haupt-und offensichtliche Vorteil der Verwendung eines verwalteten Zeiger, die hier—und anderswo im Allgemeinen—ist, dass es weiter gültig bleiben (wieder, in seinem stack frame Lebensdauer), auch als
oic
—selbst ein Referenz-Typ-Instanz zugewiesen, in der GC heap verschoben werden kann, um während der garbage collection. Das ist ein gigantischer Unterschied versus native Zeiger.Wie oben skizziert, die ref-getter ist ein
static
extension-Methode, die deklariert werden kann und/oder von überall aus genutzt. Aber wenn du in der Lage bist, zu erstellen Sie Ihre eigenen Klasse, die abgeleitet ausOfInterestClass
(das ist, wennOfInterestClass
ist nicht versiegelt), können Sie diese sogar noch schöner. In einer abgeleiteten Klasse, Sie können aufzudecken die C# - syntax für die Verwendung der Basisklasse privaten Bereich, als ob es eine öffentliche Feld Ihrer abgeleiteten Klasse. Um dies zu tun, fügen Sie einfach eine C# nur-lese - ref return Eigenschaft zu Ihrer Klasse, die bindet die statische ref-get-Methode die aktuelle Instanzthis
:Hier, das Anwesen ist aus
public
so kann jeder Zugriff auf das Feld (über einen Verweis auf unsere abgeleitete Klasse). Wir haben im wesentlichen veröffentlicht das private Feld aus der Basis-Klasse. Jetzt, in der abgeleiteten Klasse (oder anderswo angemessen) Sie können eine oder alle der folgenden:Wie Sie sehen können, weil die Eigenschaft, wie die früheren Methode, hat auch eine durch Verweis Rückgabewert, es verhält sich fast genau wie ein Feld funktioniert.
So, jetzt für die details. Wie schaffen Sie den statischen ref-getter Funktion, die ich oben zeigte? Mit
DynamicMethod
, das sollte trivial sein. Zum Beispiel, hier ist die IL code für ein traditionelles (von-Wert) statische getter-Funktion:Und hier ist der IL-code, den wir wollen, statt über die ref-return):
Der einzige Unterschied zu den von-Wert-get-Methode ist, dass wir die
ldflda
(load Feld Adresse) opcode stattldfld
(load-Bereich). Also, wenn Sie gut praktiziert, mitDynamicMethod
sollte es kein problem sein, richtig?Wenn Sie versuchen, rufen Sie die
DynamicMethod
Konstruktor angebenByRef
Typ als Rückgabe-Wert......die Funktion löst
NotSupportedException
mit der folgenden Meldung:Anscheinend diese Funktion nicht bekommen das memo auf C#7 und ref-zurück. Zum Glück fand ich eine einfache Lösung, die es bekommt, zu arbeiten. Wenn Sie eine non-ref-Typ in den Konstruktor als eine temporäre "dummy", aber dann sofort danach die Reflexion auf die neu erstellte
DynamicMethod
Instanz zu ändernm_returnType
privaten Bereich werden die ByRef-Typ Typ (sic.) dass Sie tatsächlich wollen, dann scheint alles zu funktionieren nur fine.Dinge zu beschleunigen, werde ich hier kurz auf die fertige generische Methode, die automatisiert den gesamten Prozess von der Erstellung/Rückgabe einer statischen ref-get-Funktion für die private Instanz-Feld
U
, dass der bereitgestellte name, und definiert in der KlasseT
.Wenn Sie wollen einfach nur den kompletten funktionierenden code, kopieren von unterhalb dieses Punktes am Ende
Zuerst müssen wir definieren einen Delegaten, der für die ref-getter, da ein
Func<T,TResult>
Delegierten mit ByRef Verwendung nicht deklariert werden. Zum Glück, die älterendelegate
syntax funktioniert für so tun (Puh!).Ort die Delegierten, zusammen mit die folgende statische Funktion in einem zentralen utility-Klasse, wo beide zugegriffen werden können, die während Ihres gesamten Projekts. Hier ist die Finale ref-getter-Erstellung Funktion, die verwendet werden können zum erstellen einer statischen ref-getter für die so genannten Instanz-Feld in jeder Klasse.
Nun wieder zum Anfang dieses Artikels, können wir leicht bieten die
__refget_m_iPrivate
Funktion, habe alles angefangen. Statt eine statische Funktion direkt geschrieben in C#, verwenden wir die statische ref-getter-Erstellung-Funktion zu erstellen, die den Rumpf der Funktion zur Laufzeit und speichern Sie es in eine statische Delegaten typisierte Feld (mit der gleichen Signatur). Die syntax für das aufrufen von in der Instanz-Eigenschaft (wie gezeigt, oben und unten wiederholt) oder anderswo, ist das gleiche, als wenn der compiler in der Lage gewesen zu schreiben, die Funktion.Schließlich zum cache, der dynamisch erstellten ref-getter, delegieren, legen Sie die folgende Zeile in
static
Klasse Ihrer Wahl. ErsetzenOfInterestClass
mit dem Typ der Basis-Klasseint
mit dem Feld Typ des privaten Feld, und ändern Sie den string-argument den Namen der private Bereich. Wenn Sie nicht in der Lage, erstellen Sie Ihre eigene Klasse, abgeleitet vonOfInterestClass
(oder nicht wollen), Sie sind fertig; nur dass dieses Feldpublic
und Sie können es nennen, wie eine Funktion übergebenOfInterestClass
Instanz zu verweisen, die können Sie Lesen, schreiben, oder überwachen Sie Ihreint
geschätzteprivate
Feld "m_iPrivate
."Optional, wenn Sie möchten, veröffentlichen Sie das versteckte Feld mit einem Reiniger oder mehrere Natürliche syntax können Sie eine (nicht-statische) proxy-Klasse von Ihrer eigenen, die entweder enthält eine Instanz—oder vielleicht sogar besser (wenn möglich), stammt aus—Bereich ausblenden Klasse
OfInterestClass.
Statt, die die Bereitstellung der Codezeile, die zuvor dargestellt, Global in einemstatic
- Klasse, legen Sie Sie in Ihren proxy-Klasse statt, und dann auch noch die folgende Zeile hinzufügen:var f_returnType = dm.GetType().GetField("m_returnType", bf); if (f_returnType == null) f_returnType = dm.GetType().GetField("returnType", bf); f_returnType.SetValue(dm, typeof(U).MakeByRefType());
Ldflda
? Vielleicht mit so etwas wieSystem.Runtime.CompilerServices.Unsafe
?ref
wenn Sie nur wollen, nur-lese-Zugriff auf ein Feld speichert einen Verweis-Typ?Nein, es gibt keine einfache Möglichkeit zum erstellen einer Stellvertretung get/set ein Feld.
Haben Sie, um Ihren eigenen code zu geben, die Funktionalität. Ich würde vorschlagen, zwei Funktionen in einer gemeinsam genutzten Bibliothek zur Verfügung zu stellen.
Ihren code verwenden (in diesem Beispiel habe ich nur die Erstellung der get-delegieren):
Dies macht es einfach zu erstellen Sie eine get-delegieren von einer FieldInfo (vorausgesetzt, das Feld ist vom Typ int):
Oder wenn wir ändern Ihren code ein wenig:
Dies macht es noch einfacher:
Es ist auch möglich, diese Abgeordneten mit IL, aber code wäre komplexer und hat nicht viel mehr Leistung, wenn überhaupt.
No there is no easy way to create a delegate to get/set a field.
das beantwortet meine Frage (bereits Hinzugefügt von Ritchie). Der rest ist lediglich ein refactoring der code, den ich bereits gepostet in der Frage zu nützlichen Methoden. Trotzdem vielen Dank für Geläute in. Btw, können Sie vermeiden(Func<S,T>)
wirft in Ihrem Hilfsfunktionen. nichts viel, nur der LesbarkeitIch bin mir nicht bewusst, wenn Sie verwenden würden
Expression
, warum dann die Vermeidung von Reflexion? Die meisten Operationen derExpression
beruhen auf Reflexion.GetValue
undSetValue
selbst sind dieget method
undset method
für die Felder, aber Sie sind nicht für einen bestimmten Bereich.Felder sind nicht wie die Eigenschaften sind Sie die Felder, und es gibt keinen Grund zum generieren von get - /set-Methoden für jeden. Aber der Typ kann variieren mit verschiedenen Feldes und damit
GetValue
undSetValue
definiert sind, dieparameter/return value
alsobject
für die Varianz.GetValue
ist auch eine abstrakte Methode, das heißt, für jede Klasse(noch Reflexion) überschreiben, die es werden müssen, innerhalb der gleichen Signatur.Wenn Sie nicht Typ, dann sollte der folgende code tun:
aber wenn Sie wollen, gibt es eine eingeschränkte Möglichkeit:
Dem Grund, dass das
Getter
nochFunc<S, object>
, möchten Sie vielleicht einen Blick:Kovarianz und Kontravarianz in C#, Teil Drei: Methode Gruppe-Konvertierung Varianz auf Herr Lippert ' s blog.
OpCodes.Callvirt
GetValue
undSetValue
; aber diese Methoden sind nicht gebunden an bestimmte Klassen. So ist es nicht, hängt davon abhow I ..
es hängt davon ab, wie die Sprache implementiert ist ..GetValue
undSetValue
sind beide Teil der Reflexion Welt. Die Schaffung einer Stellvertretung diese Funktion ist schnell. Ruft Sie ist immer noch langsamer, weil Sie die generische (für alle Arten von Feldern). Fordern Sie eine million mal ist 1.000.000 x langsam. Und ich bin nicht einmal reden über boxing und unboxing. Wenn Sie ein Stück code mit generischen du aktuelle Funktionen erstellen, WIEGetValue
undSetValue
, aber nur spezialisierte und high-speed. Also in beiden Fällen haben Sie ein Stück code, aber das, was Stück code, das würden Sie bevorzugen?Hier ist eine andere option für das erstellen einer delegieren, wenn Sie mit Objekten arbeiten (weiß nicht, bestimmten Typ eines Feldes). Obwohl es langsamer ist, wenn das Feld einer Struktur (wegen der Boxen).
ref return
Einschränkung inDynamicMethod
scheint Weg zu sein zumindest auf v4.0.30319.Geändert diese Antwort von Glenn Slayden mit info von microsoft docs:
Ausgänge: