2009-04-22 2 views
19

में MethodCallExpression से विधि को कैसे कॉल करें मेरे पास एक विधि कॉल अभिव्यक्ति है और विधि को आमंत्रित करने का प्रयास करें। मैंने एक रास्ता निकाला, लेकिन मुझे पैरामीटर मानों को पुनः प्राप्त करने में समस्याएं हैं क्योंकि प्रत्येक तर्क को कॉन्स्टेंटएक्सप्रेस के साथ वर्णित नहीं किया गया है।सी #

Expression<Action<T>> = t => t.DoSomething(Par0, Par1, Par2); 
MethodCallExpression methodCallExpression = selector.Body 
               as MethodCallExpression; 

// get the information which is needed to invoke the method from the provided 
// lambda expression. 
MethodInfo methodInfo = methodCallExpression.Method; 
object[] arguments = methodCallExpression.Arguments.OfType<ConstantExpression>() 
          .Select(p => p.Value).ToArray(); 

// invoke the expression on every item within the enumerable 
foreach (TSource item in source) 
{ 
    methodInfo.Invoke(item, arguments); 
} 

साथ ही, मैं विधि आह्वान करने के लिए कुछ अन्य तरीकों से देखा है, अब मुझे यकीन है कि क्या यह करने के लिए सही तरीका है नहीं कर रहा हूँ।

var func = expression.Compile(); 
var success = func.Invoke(); 

तो मेरे सवाल का, मैं कैसे methodCallExpression.Arguments से विधि तर्क मान प्राप्त कर सकते हैं कर रहा है?

या मेरे लक्ष्य को प्राप्त करने का कोई आसान तरीका है?

उत्तर

21

आपको तर्कों को पुनर्प्राप्त करने और MethodInfo को स्वयं कॉल करने के बारे में चिंता करने की आवश्यकता नहीं है, तो आप .NET को आपके लिए ऐसा करने दे सकते हैं। आपको बस इतना करना है कि उस विधि युक्त लैम्ब्डा अभिव्यक्ति बनाएं।

उदाहरण के लिए।

MethodCallExpression expression = GetExpressionSomeHow(); 
object result = Expression.Lambda(expression).Compile().DynamicInvoke(); 

इस तरह मैं अपने लिंक प्रदाता में घोंसला वाले प्रश्नों से निपटता हूं।

संपादित करें: वास्तव में, ऐसा लगता है कि आपके पास चयनकर्ता चर में पहले से ही LambdaExpression हो सकता है। उस मामले में, तुम सिर्फ संकलन और यह सीधे आह्वान करने के लिए सक्षम होना चाहिए:

object result = selector.Compile().DynamicInvoke(); 
+2

धन्यवाद, यह बहुत आसान है। मैं इसे इस तरह कर रहा हूं: // आवेदक के लिए प्रतिनिधि प्राप्त करने के लिए लैम्ब्डा अभिव्यक्ति संकलित करें। एक्शन एक्शन = selector.Compile(); // संख्या foreach (स्रोत में टीएसओएस आइटम) { कार्रवाई (आइटम) के भीतर प्रत्येक आइटम पर अभिव्यक्ति का आह्वान करें; } और अंततः मुझे इस मुद्दे के लिए एमएसडीएन दस्तावेज भी मिला: http://msdn.microsoft.com/en-us/library/bb882536.aspx – Enyra

+0

क्या कोई कारण नहीं है कि आप केवल 'चयनकर्ता' नहीं कर सकते हैं। कॉम्पाइल()() '? ब्रांड्स काम करते समय 'Invoke' या 'DynamicInvoke' क्यों? – ErikE

6

संकलन एक अभिव्यक्ति एक बहुत ही गहन आपरेशन है, इसलिए मैं केवल यह है कि यदि आप की योजना बना रहे अभिव्यक्ति पुनः उपयोग करना होगा। मैं अन्यथा प्रतिबिंब के तरीके की सिफारिश करेंगे; आप इसे तेजी से निष्पादित करेंगे। अभिव्यक्ति को कभी भी कॉल न करें। कॉम्पाइल() एक तंग पाश में।

2

@ Ch00k < - धन्यवाद, अच्छी व्याख्या। मैं बस

selector.Compile(); 

आपको एक प्रतिनिधि देना चाहता है। एक उदाहरण विधि के लिए आपको इस विधि को कॉल करने के लिए एक उदाहरण की आवश्यकता है। आप आला

// Grab the method from MyClass - param1 and param2 are the actual parameters you 
// want to pass to the method call. 
Expression<Func<MyClass, TValue>> selector = (x => x.MyMethod(param1, param2)); 

// Create an instance of MyClass to call the method on 
var myClass = new MyClass(); 

// Call the method on myClass through DynamicInvoke 
object returnValue = selector.Compile().DynamicInvoke(myClass); 
0

मैं इस कोशिश करेगा वस्तु लौटने के लिए DynamicInvoke को तर्क के रूप में इस उदाहरण से पारित:

LambdaExpression l = Expression.Lambda(Expression.Convert(element, element.Type)); 
return l.Compile().DynamicInvoke(); 
1

हैं:

private static object _getValue(MethodCallExpression expression) 
{ 
    var objectMember = Expression.Convert(expression, typeof(object)); 

    var getterLambda = Expression.Lambda<Func<object>>(objectMember); 

    var getter = getterLambda.Compile(); 

    return getter(); 
} 

यह बहुत तेजी से निम्नलिखित बुला सकता है आप अपनी अभिव्यक्ति.call को एक्शन या फनक में संकलित करना चाहते हैं, यह है कि आप कैसे करते हैं:

var method = typeof(MyType).GetMethod(nameof(MyType.MyMethod), BindingFlags.Public | BindingFlags.Static); 
var parameter = Expression.Parameter(typeof(string), "s"); 
var call = Expression.Call(method, parameter); 
var lambda = Expression.Lambda<Func<string, int>>(call, call.Arguments.OfType<ParameterExpression>()); 
var func = lambda.Compile(); 
int result = func("sample string input"); 

यह आपको बस func.Invoke ("mystring") या func ("my string") करने की अनुमति देता है;

यहां रहस्य यह है कि आपको अभिव्यक्ति बनाने के दौरान उपयोग किए गए समान पैरामीटर को पारित करने की आवश्यकता है। अन्यथा आपको "अमान्य ऑपरेशन अपवाद" चर के प्रकार 'सिस्टम' प्रकार की त्रुटि मिलती है। सिस्टम 'स्ट्रिंग' से संदर्भित '' , लेकिन यह परिभाषित नहीं है।