Hallo zusammen!
Wir verwenden hier in einer Firma eine Komponente, die wir an einer bestimmten Stelle erweitern wollen. Allerdings ist diese Komponente dazu keine Möglichkeit. Wir müssen aber eigentlich nur eine Methode austauschen...
Ich habe System.Reflection.Emit.MethodRental.SwapMethodBody gefunden, allerdings ist die Methode recht schlecht dokumentiert und sie funktioniert auch nur wenn man eine Klasse dynamisch zusammenbaut.
Gibt es irgendeine andere Möglichkeit, einen Methodenkörper zur Laufzeit durch einen anderen auszutauschen?
Viele Grüße,
Simon
Wir verwenden hier in einer Firma eine Komponente, die wir an einer bestimmten Stelle erweitern wollen.
Heißt das, dass diese Komponente nicht von Euch kommt? Für mich hört sich Deine Idee ein wenig gefährlich an, da schnell den Überblick verlieren kann, wo eine Methode ausgetauscht wurde. Kannst Du nicht eventuell, falls die Schnittstelle, die Ihr verwendet nicht einfach dekorieren (Decorator Pattern)? Gibt es denn dazu ein Interface?
Gruß, DaMoe
Hallo DaMoe80!
Die Komponente ist nicht von uns.
Für mich hört sich Deine Idee ein wenig gefährlich an, da schnell den Überblick verlieren kann, wo eine Methode ausgetauscht wurde
Soweit ich weiß ist das die einzige Möglichkeit. Und es ist nur eine Methode, da dürfte das kein Problem sein.
die Ihr verwendet nicht einfach dekorieren (Decorator Pattern
Nein, das ist leider nicht möglich 😦. Wir müssen die private Methode austauschen.
Viele Grüße,
Simon
Wenns net unbedingt zur Laufzeit sein soll (oder vielleicht gehts auch da, weiß net genau), dann ist Cecil viellicht was für dich.
Baka wa shinanakya naoranai.
Mein XING Profil.
Hallo talla!
Es muss leider ungebedingt zur Laufzeit sein.
Viele Grüße,
Simon
Warum?
Erklär mal lieber was es ergeben soll, nicht wie ihr meint es machen zu wollen.
Funktionen zur Laufzeit tauschen gibt und nennt sich delegaten. Die Anwendung muss dafür aber konzipiert sein.
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
Hallo SimonKnight6600,
so wie ich sehe ist dein Problem mit der SwapMethodBody-Methode das du keinen Token für die zu modifizierende Methode bekommst. Du kannst an den Token gelangen in dem du die MethodInfo der Methode wiederrum per Reflection untersuchst. puh
Das MethodInfo Objekt hat ein nicht öffentliche Eigenschaft "MethodToken". Wenn du diese hast brauchst du nur noch einen IntPtr auf ein Byte-Array welches den ILCode enthält. Das Array mit dem Code bekommst du über GetMethodBody().GetILAsByteArray(). (Von der neuen Methode)
Gruss
tscherno
Hallo SimonKnight6600,
ich kann auch nicht ganz verstehen, warum die Methode unbedingt zur Laufzeit auszutauschen ist. Ist es nicht "besser", wenn man die bestehende Komponente nimmt, und in dieser dann die private Methode austauscht?
Ich würde da direkt über den IL Code gehen, und anstatt austauschen würde ich eine Art Umleitung vorschlagen, so dass eine neue Methode (die Deine) mit eingebaut wird, und überall wo auf die originale Methode verwiesen wird einfach auf Deine neue zu verweisen. Da es eine private Methode ist, hat sie auch einen begrenzten Gültigkeitsbereich, wo man sicher gehen kann, dass auch alle aufrufende Stellen gefunden werden kann.
Auf den Zielrechnern kann man dann die originale mit der veränderten Komponente austauschen, und fertig.
Grüße
Norman-Timo
A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”
Hallo tscherno!
Danke für deine Tipps. Auf diesem Weg konnte ich die Methode aufrufen, allerdings scheint das nicht bei bereits erstellten Typen (die nicht dynamisch angelegt werden) zu funktionieren:
Type t = typeof(TestClass);
MethodInfo methodToSwap = t.GetMethod("PrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance);
MemberInfo mb = (MemberInfo)methodToSwap;
PropertyInfo[] infos = methodToSwap.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance );
int token = mb.MetadataToken;
// So bin ich nicht an die Property rangekommen, darum hab ichs mit dem MemberInfo Cast oben probiert. Daran liegts aber nicht!
// int token = Convert.ToInt32(mb.GetProperty("MetadataToken", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(mb, null));
byte[] ilCode = this.GetType().GetMethod("NewMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetMethodBody().GetILAsByteArray();
GCHandle handle = GCHandle.Alloc(ilCode, GCHandleType.Pinned);
IntPtr pointer = handle.AddrOfPinnedObject();
MethodRental.SwapMethodBody(t, token, pointer, ilCode.Length, 0);
handle.Free();
t.GetMethod("PrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance).Invoke( null, new object[]{});
Die MethodRental.SwapMethodBody-Methode kann nur aufgerufen werden, um den Methodentext in einem dynamischen Modul auszulagern.
Hallo norman_timo!
Die Assembly ist wie gesagt eine Drittkomponente und Änderungen daran sind nicht erlaubt.
Viele Grüße,
Simon
Hallo SimonKnight6600,
Die Assembly ist wie gesagt eine Drittkomponente und Änderungen daran sind nicht erlaubt.
Ob man die Änderungen nun im Arbeitsspeicher macht, oder direkt in der Datei, das spielt rechtlich gesehen keinen Unterschied. Einziger Vorteil beim "Ändern im Arbeitsspeicher" wäre die Nachweisbarkeit, die dadurch natürlich erheblich erschwert werden würde.
Aber wie gesagt ein Ändern ist ein Ändern, und da ist es gleich, ob in der Datei oder im Speicher...
Grüße
Norman-Timo
A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”
Hallo norman_timo!
Wir werden uns mal mit dem Hersteller von der Komponente in Verbindung setzen, ob es nicht eine andere Lösung gibt. (So dass wir das gewünschte ohne die Methode erreichen oder der Hersteller die Klasse ändert)
Vielen Dank,
Simon