दिलचस्प पोस्ट
पायथन में फ़ंक्शन से मैं दो मान कैसे वापस कर सकता हूँ? पायथन कोड ओब्बुस्केक्शन मैं "खोज" से सभी "अनुमति अस्वीकृत" संदेशों को कैसे बाहर निकाल सकता हूं? मोंगो डीबी: एक से कई संग्रहों से डेटा एकत्र करें..कैसे? सी में "अप्रयुक्त पैरामीटर" चेतावनी जाँच करें कि विशिष्ट सरणी कुंजी बहुआयामी सरणी में मौजूद है – PHP एक डबल की स्ट्रिंग फ़ॉर्मेटिंग Sqlite स्ट्रिंग को तिथि में कनवर्ट करें निर्माता विरासत क्या है? टी-एसक्यूएल में पिवट डेटा क्या ऐरे और ऑब्जेक्ट में स्पेस का हिस्सा है? आईओएस 4 में गैर-आइपॉड संगीत को नियंत्रित करने के लिए पृष्ठभूमि में आईपॉड कंट्रोल कैसे सक्षम करें? Google क्रोम एक्सटेंशन पॉपअप कैसे खोलें? क्या रब्बी के पास असली मल्टीथ्रेडिंग है? HTML से angular2 घटक के चयनकर्ता टैग को कैसे हटाए / बदलना है

गतिशील रूप से सी # विधि की सामग्री को बदलते हैं?

मैं क्या करना चाहता हूं यह कैसे बदल जाता है कि सी # विधि कहां बुलाया जाता है, ताकि मैं कुछ इस तरह लिख सकता / सकती हूं:

[Distributed] public DTask<bool> Solve(int n, DEvent<bool> callback) { for (int m = 2; m < n - 1; m += 1) if (m % n == 0) return false; return true; } 

रन-टाइम में, मुझे उन विधियों का विश्लेषण करने में सक्षम होने की आवश्यकता होती है जिनके वितरित विशेषता (जो मैं पहले से ही कर सकता हूँ) और फ़ंक्शन निष्पादित किए जाने के बाद और फ़ंक्शन रिटर्न के बाद कोड को सम्मिलित करते हैं। इससे भी महत्वपूर्ण बात, मुझे कोड को संशोधित किए बिना ऐसा करने में सक्षम होना चाहिए, जहां समाधान को कहा जाता है या समारोह की शुरुआत में (समय संकलन में, ऐसा समय-समय पर करना उद्देश्य होता है)।

फिलहाल मैंने इस बिट कोड का प्रयास किया है (मान लें कि वह प्रकार है जिसका समाधान है में संग्रहित है, और मी समाधान का एक तरीका है) :

 private void WrapMethod(Type t, MethodInfo m) { // Generate ILasm for delegate. byte[] il = typeof(Dpm).GetMethod("ReplacedSolve").GetMethodBody().GetILAsByteArray(); // Pin the bytes in the garbage collection. GCHandle h = GCHandle.Alloc((object)il, GCHandleType.Pinned); IntPtr addr = h.AddrOfPinnedObject(); int size = il.Length; // Swap the method. MethodRental.SwapMethodBody(t, m.MetadataToken, addr, size, MethodRental.JitImmediate); } public DTask<bool> ReplacedSolve(int n, DEvent<bool> callback) { Console.WriteLine("This was executed instead!"); return true; } 

हालांकि, MethodRental.SwapMethodBody केवल डायनामिक मॉड्यूल पर काम करता है; जिन लोगों को पहले से ही विधानसभा में संकलित और संग्रहित नहीं किया गया है

इसलिए मैं किसी विधि पर स्वैप-विधिबीडी प्रभावी रूप से करने के लिए एक रास्ता खोज रहा हूं जो पहले से लोड किए गए और क्रियान्वित विधानसभा में संग्रहीत है

नोट, यह एक मुद्दा नहीं है यदि मुझे पूरी तरह से गतिशील मॉड्यूल में विधि की प्रतिलिपि बनाना है, लेकिन इस मामले में मुझे आईएल में प्रतिलिपि बनाने के साथ-साथ हल करने के लिए सभी कॉलों को अपडेट करने की ज़रूरत है नई प्रति को इंगित करेंगे

वेब के समाधान से एकत्रित समाधान "गतिशील रूप से सी # विधि की सामग्री को बदलते हैं?"

बस इस निहितार्थ के बारे में सोचें यदि यह संभव हो। उदाहरण के लिए आप String क्लास की सामग्री को बदल सकते हैं और कूड़ा हुआ कगार पर पहुंच सकते हैं। सीएलआर द्वारा एक बार विधि भरी हुई है, इसे संशोधित नहीं किया जा सकता है। आप एओपी और पुस्तकालयों जैसे कैसल डायनेमिक प्रोक्सी के बारे में एक नज़र डाल सकते हैं, जिसका उपयोग राइनो मोक्स जैसी चौखटे के मजाक के लिए किया जाता है

.NET 4 और इसके बाद के संस्करण के लिए

 using System; using System.Reflection; using System.Runtime.CompilerServices; namespace InjectionTest { class Program { static void Main(string[] args) { Target targetInstance = new Target(); targetInstance.test(); Injection.install(1); Injection.install(2); Injection.install(3); Injection.install(4); targetInstance.test(); Console.Read(); } } public class Target { public void test() { targetMethod1(); Console.WriteLine(targetMethod2()); targetMethod3("Test"); targetMethod4(); } private void targetMethod1() { Console.WriteLine("Target.targetMethod1()"); } private string targetMethod2() { Console.WriteLine("Target.targetMethod2()"); return "Not injected 2"; } public void targetMethod3(string text) { Console.WriteLine("Target.targetMethod3("+text+")"); } private void targetMethod4() { Console.WriteLine("Target.targetMethod4()"); } } public class Injection { public static void install(int funcNum) { MethodInfo methodToReplace = typeof(Target).GetMethod("targetMethod"+ funcNum, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); MethodInfo methodToInject = typeof(Injection).GetMethod("injectionMethod"+ funcNum, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); RuntimeHelpers.PrepareMethod(methodToReplace.MethodHandle); RuntimeHelpers.PrepareMethod(methodToInject.MethodHandle); unsafe { if (IntPtr.Size == 4) { int* inj = (int*)methodToInject.MethodHandle.Value.ToPointer() + 2; int* tar = (int*)methodToReplace.MethodHandle.Value.ToPointer() + 2; #if DEBUG Console.WriteLine("\nVersion x86 Debug\n"); byte* injInst = (byte*)*inj; byte* tarInst = (byte*)*tar; int* injSrc = (int*)(injInst + 1); int* tarSrc = (int*)(tarInst + 1); *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5); #else Console.WriteLine("\nVersion x86 Release\n"); *tar = *inj; #endif } else { long* inj = (long*)methodToInject.MethodHandle.Value.ToPointer()+1; long* tar = (long*)methodToReplace.MethodHandle.Value.ToPointer()+1; #if DEBUG Console.WriteLine("\nVersion x64 Debug\n"); byte* injInst = (byte*)*inj; byte* tarInst = (byte*)*tar; int* injSrc = (int*)(injInst + 1); int* tarSrc = (int*)(tarInst + 1); *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5); #else Console.WriteLine("\nVersion x64 Release\n"); *tar = *inj; #endif } } } private void injectionMethod1() { Console.WriteLine("Injection.injectionMethod1"); } private string injectionMethod2() { Console.WriteLine("Injection.injectionMethod2"); return "Injected 2"; } private void injectionMethod3(string text) { Console.WriteLine("Injection.injectionMethod3 " + text); } private void injectionMethod4() { System.Diagnostics.Process.Start("calc"); } } } 

आप रनटाइम पर किसी विधि की सामग्री को संशोधित कर सकते हैं लेकिन आपको नहीं चाहिए, और यह दृढ़ता से अनुशंसा की जाती है कि परीक्षण प्रयोजनों के लिए

बस एक नज़र है:

http://www.codeproject.com/Articles/463508/NET-CLR-Injection-Modify-IL-Code-during-Run-time

असल में, आप यह कर सकते हैं:

  1. MethodInfo.GetMethodBody () के द्वारा आईएल विधि सामग्री प्राप्त करें। GetILAsByteArray ()
  2. इन बाइट्स के साथ मेसें।

    यदि आप बस कुछ कोड को जोड़ना चाहते हैं या जोड़ सकते हैं, तो बस प्रीपेन्ड / अप्कोड जोड़ना चाहते हैं (स्टैक को साफ करने के बारे में सावधान रहें, हालांकि)

    मौजूदा आईएल को "असंपल" करने के कुछ सुझाव यहां दिए गए हैं:

    • दिए गए बाइट आईएल के अनुदेशों का अनुक्रम हैं, उनके तर्कों के बाद (यदि उनके पास कुछ है – उदाहरण के लिए, '।' कॉल में एक तर्क होता है: बुलाया गया तरीका टोकन और '। Pop' में कोई नहीं है)
    • आईआर कोड और बाइट्स के बीच पत्राचार जो आप लौटे हुए सरणी में पाते हैं, OpCodes.YourOpCode.Value (जो कि आपके असेंबली में सहेजे गए वास्तविक ऑपोडोड बाइट मान है) का उपयोग करते हुए पाया जा सकता है।
    • आईएल कोड में अलग-अलग आकार (एक से कई बाइट्स) हो सकते हैं, के बाद तर्क जोड़ा गया है, ओपोड पर निर्भर करते हुए कहा जाता है
    • आप ऐसे टोकन पा सकते हैं जो शोध के तर्कों को उपयुक्त तरीकों के माध्यम से संदर्भित कर रहे हैं। उदाहरण के लिए, यदि आपका आईएल "। कॉल 354354" (हेक्सा में 28 00 05 68 32 के रूप में कोडित है, 28h = 40 है '' कॉल 'opcode और 56832 एच = 354354), इसी विधि का उपयोग MethodBase.GetMethodFromHandle (354354 )
  3. एक बार संशोधित होने पर, आप आईआईएल बाइट सरणी को इंजेक्शनहेल्पर। अपडेटीएलकोड (विधिइन्फो विधि, बाइट [] आईएलकोड्स के माध्यम से फिर से किया जा सकता है – ऊपर उल्लेखित लिंक देखें

    यह "असुरक्षित" हिस्सा है … यह अच्छी तरह से काम करता है, लेकिन इसमें आंतरिक सीएलआर तंत्रों में हैकिंग होते हैं …

सद्भाव एक ओपन सोर्स लाइब्रेरी है जिसे रनटाइम के दौरान किसी भी प्रकार की मौजूदा सी # विधियों को बदलने, सजाने या संशोधित करने के लिए डिज़ाइन किया गया है। यह मुख्य फोकस मोनो में लिखा गया खेल और प्लगइन्स है, लेकिन इस तकनीक का उपयोग किसी भी एनएटी संस्करण के साथ किया जा सकता है। यह एक ही विधि (वे अधिलेखित करने के बजाए जमा करते हैं) में कई बदलावों का ख्याल रखता है।

यह प्रत्येक मूल पद्धति के लिए प्रकार डायनेमिकम पद्धति के तरीकों का निर्माण करता है और उस पर कोड का उत्सर्जन करता है जो प्रारंभ और अंत में कस्टम विधियों को कॉल करता है। यह आपको मूल आईएल कोड की प्रक्रिया के लिए फिल्टर लिखने की अनुमति देता है जो मूल विधि के अधिक विस्तृत हेरफेर की अनुमति देता है।

प्रक्रिया को पूरा करने के लिए, यह मूल विधि के ट्रैम्पोलिन में एक सरल कोडर कूदता लिखता है जो गतिशील विधि संकलन से उत्पन्न कोडल को इंगित करता है। यह विंडोज़, मैकोड और किसी भी लिनक्स पर 32/64 बिट के लिए काम करता है जो मोनो का समर्थन करता है।

आप इसे बदल सकते हैं यदि विधि गैर आभासी, गैर सामान्य है, सामान्य प्रकार में नहीं है, इनलाइन नहीं है और x86 प्लेटफ़ॉर्म पर:

 MethodInfo methodToReplace = ... RuntimeHelpers.PrepareMetod(methodToReplace.MethodHandle); var getDynamicHandle = Delegate.CreateDelegate(Metadata<Func<DynamicMethod, RuntimeMethodHandle>>.Type, Metadata<DynamicMethod>.Type.GetMethod("GetMethodDescriptor", BindingFlags.Instance | BindingFlags.NonPublic)) as Func<DynamicMethod, RuntimeMethodHandle>; var newMethod = new DynamicMethod(...); var body = newMethod.GetILGenerator(); body.Emit(...) // do what you want. body.Emit(OpCodes.jmp, methodToReplace); body.Emit(OpCodes.ret); var handle = getDynamicHandle(newMethod); RuntimeHelpers.PrepareMethod(handle); *((int*)new IntPtr(((int*)methodToReplace.MethodHandle.Value.ToPointer() + 2)).ToPointer()) = handle.GetFunctionPointer().ToInt32(); //all call on methodToReplace redirect to newMethod and methodToReplace is called in newMethod and you can continue to debug it, enjoy. 

मुझे पता है कि यह आपके प्रश्न का सटीक उत्तर नहीं है, लेकिन यह करने का सामान्य तरीका कारखानों / प्रॉक्सी दृष्टिकोण का उपयोग कर रहा है

पहले हम एक बेस प्रकार घोषित करते हैं।

 public class SimpleClass { public virtual DTask<bool> Solve(int n, DEvent<bool> callback) { for (int m = 2; m < n - 1; m += 1) if (m % n == 0) return false; return true; } } 

तब हम एक व्युत्पन्न प्रकार की घोषणा कर सकते हैं (इसे प्रॉक्सी कहते हैं)

 public class DistributedClass { public override DTask<bool> Solve(int n, DEvent<bool> callback) { CodeToExecuteBefore(); return base.Slove(n, callback); } } // At runtime MyClass myInstance; if (distributed) myInstance = new DistributedClass(); else myInstance = new SimpleClass(); 

व्युत्पन्न प्रकार भी रनटाइम पर उत्पन्न हो सकते हैं

 public static class Distributeds { private static readonly ConcurrentDictionary<Type, Type> pDistributedTypes = new ConcurrentDictionary<Type, Type>(); public Type MakeDistributedType(Type type) { Type result; if (!pDistributedTypes.TryGetValue(type, out result)) { if (there is at least one method that have [Distributed] attribute) { result = create a new dynamic type that inherits the specified type; } else { result = type; } pDistributedTypes[type] = result; } return result; } public T MakeDistributedInstance<T>() where T : class { Type type = MakeDistributedType(typeof(T)); if (type != null) { // Instead of activator you can also register a constructor delegate generated at runtime if performances are important. return Activator.CreateInstance(type); } return null; } } // In your code... MyClass myclass = Distributeds.MakeDistributedInstance<MyClass>(); myclass.Solve(...); 

व्युत्पन्न वस्तु के निर्माण के दौरान एकमात्र प्रदर्शन हानि, पहली बार काफी धीमा है क्योंकि यह बहुत प्रतिबिंब और प्रतिबिंब उत्सर्जित करेगा। अन्य सभी समय, यह एक समवर्ती तालिका देखने और कन्स्ट्रक्टर की लागत है। जैसा कि कहा गया है, आप का उपयोग करके निर्माण का अनुकूलन कर सकते हैं

 ConcurrentDictionary<Type, Func<object>>. 

लोगमैन के समाधान , लेकिन विधि निकायों स्वैपिंग के लिए एक इंटरफेस के साथ। इसके अलावा, एक सरल उदाहरण।

 using System; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; namespace DynamicMojo { class Program { static void Main(string[] args) { Animal kitty = new HouseCat(); Animal lion = new Lion(); var meow = typeof(HouseCat).GetMethod("Meow", BindingFlags.Instance | BindingFlags.NonPublic); var roar = typeof(Lion).GetMethod("Roar", BindingFlags.Instance | BindingFlags.NonPublic); Console.WriteLine("<==(Normal Run)==>"); kitty.MakeNoise(); //HouseCat: Meow. lion.MakeNoise(); //Lion: Roar! Console.WriteLine("<==(Dynamic Mojo!)==>"); DynamicMojo.SwapMethodBodies(meow, roar); kitty.MakeNoise(); //HouseCat: Roar! lion.MakeNoise(); //Lion: Meow. Console.WriteLine("<==(Normality Restored)==>"); DynamicMojo.SwapMethodBodies(meow, roar); kitty.MakeNoise(); //HouseCat: Meow. lion.MakeNoise(); //Lion: Roar! Console.Read(); } } public abstract class Animal { public void MakeNoise() => Console.WriteLine($"{this.GetType().Name}: {GetSound()}"); protected abstract string GetSound(); } public sealed class HouseCat : Animal { protected override string GetSound() => Meow(); private string Meow() => "Meow."; } public sealed class Lion : Animal { protected override string GetSound() => Roar(); private string Roar() => "Roar!"; } public static class DynamicMojo { /// <summary> /// Swaps the function pointers for a and b, effectively swapping the method bodies. /// </summary> /// <exception cref="ArgumentException"> /// a and b must have same signature /// </exception> /// <param name="a">Method to swap</param> /// <param name="b">Method to swap</param> public static void SwapMethodBodies(MethodInfo a, MethodInfo b) { if (!HasSameSignature(a, b)) { throw new ArgumentException("a and b must have have same signature"); } RuntimeHelpers.PrepareMethod(a.MethodHandle); RuntimeHelpers.PrepareMethod(b.MethodHandle); unsafe { if (IntPtr.Size == 4) { int* inj = (int*)b.MethodHandle.Value.ToPointer() + 2; int* tar = (int*)a.MethodHandle.Value.ToPointer() + 2; byte* injInst = (byte*)*inj; byte* tarInst = (byte*)*tar; int* injSrc = (int*)(injInst + 1); int* tarSrc = (int*)(tarInst + 1); int tmp = *tarSrc; *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5); *injSrc = (((int)tarInst + 5) + tmp) - ((int)injInst + 5); } else { throw new NotImplementedException($"{nameof(SwapMethodBodies)} doesn't yet handle IntPtr size of {IntPtr.Size}"); } } } private static bool HasSameSignature(MethodInfo a, MethodInfo b) { bool sameParams = !a.GetParameters().Any(x => !b.GetParameters().Any(y => x == y)); bool sameReturnType = a.ReturnType == b.ReturnType; return sameParams && sameReturnType; } } } 

आप ICLRPRofiling इंटरफेस का उपयोग करके रनटाइम पर एक विधि को बदल सकते हैं

  1. प्रक्रिया को संलग्न करने के लिए कॉल अटैकप्रोफाइलर ।
  2. विधि कोड को बदलने के लिए SetILFunctionBody पर कॉल करें

अधिक जानकारी के लिए इस ब्लॉग को देखें।

कुछ चौराहे मौजूद हैं जो आपको रनटाइम पर किसी भी तरीके को गतिशील रूप से बदलने की अनुमति देता है (वे उपयोगकर्ता 152949 द्वारा उल्लिखित आईसीएलआरप्रोफाइलिंग इंटरफेस का उपयोग करते हैं):

  • प्रेग : फ्री और ओपन सोर्स!
  • माइक्रोसॉफ्ट फ़ेक्स : वाणिज्यिक, विजुअल स्टूडियो प्रीमियम और अल्टीमेट में शामिल है, लेकिन समुदाय और व्यावसायिक नहीं
  • टेलरिक जस्टमॉक : वाणिज्यिक, एक "लाइट" संस्करण उपलब्ध है
  • टाइपेमोक अलगाव : वाणिज्यिक