2011-09-23 6 views
7

तो यह करने के लिए स्पष्ट तरीका है ..स्ट्रिंग नाम से विधि को कॉल करने के लिए .Net 3.5 में सबसे तेज़ तरीका क्या है?

var handler = GetType().GetMethod(methodName, BindingFlags.NonPublic | 
               BindingFlags.Instance); 

handler.Invoke(this, new object[] {e}); 

और मैं तरीकों के आसपास रखने के लिए कैशिंग जोड़ सकते हैं लेकिन अगर वहाँ एक पूरी तरह से अलग है और तेजी से जिस तरह से मैं सोच रहा हूँ?

उत्तर

15

एक टाइप किए गए प्रतिनिधि को कैश करना सबसे तेज़ तरीका होगा; यदि आप जानते हैं हस्ताक्षर हमेशा होता है:

void PersonInstance.MethodName(string s); 

तो फिर तुम बना सकते हैं Delegate.CreateDelegate के माध्यम से एक Action<Person,string>:

var action = (Action<Person,string>)Delegate.CreateDelegate(
    typeof(Action<Person,string>), method); 

यह तो नाम के खिलाफ कैश हो सकता है, और के रूप में अनुरोध किया गया:

action(personInstance, value); 

ध्यान दें कि यहां कैश महत्वपूर्ण है; विधि का पता लगाने और टाइप किए गए प्रतिनिधि को तैयार करने के प्रतिबिंब गैर-तुच्छ है।

हस्ताक्षर अप्रत्याशित है, तो यह कठिन हो जाता है, क्योंकि डायनामिक इनवोक अपेक्षाकृत धीमी है। सबसे तेज़ तरीका डायनामिक मोड और आईएलजीनरेटर का उपयोग एक शिम विधि (फ्लाई पर) लिखने के लिए किया जाएगा जो पैरामीटर और अनपॅक के लिए ऑब्जेक्ट [] लेता है और हस्ताक्षर से मेल खाता है - फिर आप Action<object, object[]> या Func<object,object[],object> स्टोर कर सकते हैं। हालांकि, यह एक उन्नत विषय है। यदि वास्तव में आवश्यकता हो तो मैं एक उदाहरण प्रदान कर सकता हूं। अनिवार्य रूप से (क्रम में) लिख:

void DummyMethod(object target, object[] args) { 
    ((Person)target).MethodName((int)args[0],(string)args[1]); 
} 

यहाँ कि (ध्यान दें करने का एक उदाहरण है: यह इस समय ref/out आर्ग, और संभवतः कुछ अन्य स्थितियों को संभाल नहीं करता है - और मैं छोड़ दिया है " कैश पाठक के लिए एक व्यायाम के रूप चीजों की "पक्ष):

using System; 
using System.Reflection; 
using System.Reflection.Emit; 

class Program 
{ 
    static void Main() 
    { 
     var method = typeof(Foo).GetMethod("Bar"); 
     var func = Wrap(method); 
     object[] args = { 123, "abc"}; 
     var foo = new Foo(); 
     object result = func(foo, args); 
    } 

    static Func<object, object[], object> Wrap(MethodInfo method) 
    { 
     var dm = new DynamicMethod(method.Name, typeof(object), new Type[] { 
      typeof(object), typeof(object[]) 
     }, method.DeclaringType, true); 
     var il = dm.GetILGenerator(); 

     if (!method.IsStatic) 
     { 
      il.Emit(OpCodes.Ldarg_0); 
      il.Emit(OpCodes.Unbox_Any, method.DeclaringType); 
     } 
     var parameters = method.GetParameters(); 
     for (int i = 0; i < parameters.Length; i++) 
     { 
      il.Emit(OpCodes.Ldarg_1); 
      il.Emit(OpCodes.Ldc_I4, i); 
      il.Emit(OpCodes.Ldelem_Ref); 
      il.Emit(OpCodes.Unbox_Any, parameters[i].ParameterType); 
     } 
     il.EmitCall(method.IsStatic || method.DeclaringType.IsValueType ? 
      OpCodes.Call : OpCodes.Callvirt, method, null); 
     if (method.ReturnType == null || method.ReturnType == typeof(void)) 
     { 
      il.Emit(OpCodes.Ldnull); 
     } 
     else if (method.ReturnType.IsValueType) 
     { 
      il.Emit(OpCodes.Box, method.ReturnType); 
     } 
     il.Emit(OpCodes.Ret); 
     return (Func<object, object[], object>)dm.CreateDelegate(typeof(Func<object, object[], object>)); 
    } 
} 

public class Foo 
{ 
    public string Bar(int x, string y) 
    { 
     return x + y; 
    } 
} 
+0

मैं DynamicMethod और ILGenerator उपयोग का एक उदाहरण देखने के लिए (अगर यह बहुत ज्यादा मुसीबत नहीं है) चाहते हैं। – StriplingWarrior

+2

@StriplingWarrior कोई समस्या नहीं, नहीं - मैं वर्तमान में आईपॉड पर हूं, जो आईएल-उत्सर्जन कोड लिखने के लिए खुद को उधार नहीं देता है। जब मैं एक पीसी में हूं तो मैं कुछ घंटों में एक उदाहरण जोड़ सकता हूं? –

+0

+1 अच्छा। मुझे इसे आजमा देना था और यह काम करता है! – kenny

संबंधित मुद्दे

 संबंधित मुद्दे