2011-11-22 18 views
22

मुझे पता है कि इस साइट पर कुछ जवाब हैं और मैं क्षमा चाहता हूं अगर यह किसी भी तरह से डुप्लिकेट है, लेकिन जो भी मैंने पाया है वह वह नहीं करता जो मैं कोशिश कर रहा हूं कर।अभिव्यक्ति का उपयोग कर किसी विधि का नाम प्राप्त करें

मैं विधि जानकारी निर्दिष्ट करने की कोशिश कर रहा हूं ताकि मैं तारों का उपयोग न करके एक प्रकार सुरक्षित तरीके से नाम प्राप्त कर सकूं। तो मैं इसे अभिव्यक्ति के साथ निकालने की कोशिश कर रहा हूं।

MemberInfo GetMethodInfo<T>(Expression<Action<T>> expression) 
{ 
     return ((MethodCallExpression)expression.Body).Method; 
} 

मैं इस प्रकार सहायक विधि कॉल कर सकते हैं:

public interface IMyInteface 
{ 
    void DoSomething(string param1, string param2); 
} 

वर्तमान में मैं नाम इस पद्धति का उपयोग कर सकते हैं:

मैं इस इंटरफ़ेस में एक विधि का नाम प्राप्त करना चाहते हैं कहो :

var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething(null, null)); 
Console.WriteLine(methodInfo.Name); 

लेकिन मैं इस संस्करण की तलाश में हूं कि मुझे निर्दिष्ट किए बिना विधि का नाम मिल सकता है मापदंडों (शून्य, नल)

इस तरह:

var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething); 

लेकिन सभी प्रयास

वहाँ यह करने के लिए एक रास्ता है संकलित करने के लिए असफल हो?

+0

इस समय वीएस नहीं है, लेकिन मुझे लगता है कि आपको गैर-सामान्य विकल्प में 'प्रतिनिधि' या 'क्रिया <स्ट्रिंग, स्ट्रिंग>' स्वीकार करने का प्रयास करना चाहिए। इस मामले में आपको एक विधि समूह – Snowbear

+0

पास करने में सक्षम होना चाहिए यदि मैं इनपुट में इनपुट बदलता हूं तो यह संकलित नहीं होगा और त्रुटि विधि समूह को प्रतिनिधि में परिवर्तित नहीं कर सकती है। अगर मैं इसे एक्शन <स्ट्रिंग में बदलता हूं, स्ट्रिंग> यह काम करता प्रतीत होता है लेकिन अभिव्यक्ति को यूनरीएक्सप्रेस में परिवर्तित कर दिया जाता है और विधि शून्य होती है और मैं नहीं देख सकता कि यह UnaryExpression – Andre

+0

एफ़टर कनवर्टिंग से कहां प्राप्त करें .. क्या आपने 'var methodInfo को आजमाया है = GetMethodInfo (DoSomething); 'var methodInfo = GetMethodInfo (x => x.DoSomething) के बजाय' '? साथ ही, मुझे अभी भी लगता है कि निर्दिष्ट (डिफ़ॉल्ट (स्ट्रिंग), डिफ़ॉल्ट (स्ट्रिंग)) - अधिक पठनीय है, और आप इस मामले में ओवरलोडिंग विधियों का समर्थन कर सकते हैं –

उत्तर

11
x => x.DoSomething 

आदेश में इस compilable मैं केवल दो तरीके को देखने के बनाने के लिए:

  1. जाओ गैर सामान्य तरीके से और के रूप में निर्दिष्ट के रूप में Action<string, string>
  2. पैरामीटर निर्दिष्ट Action<string, string> है आपके खुद के द्वारा लक्ष्य प्रतिनिधि के प्रकार: GetMethodInfo<IMyInteface>(x => new Action<string,string>(x.DoSomething))

अगर आप दूसरा एक है, जिसे आप तब तर्क को छोड़ करने की अनुमति देता साथ जाने के लिए ठीक है आप निम्नानुसार अपने GetMethodInfo विधि लिख सकते हैं:

MemberInfo GetMethodInfo<T>(Expression<Func<T, Delegate>> expression) 
    { 
     var unaryExpression = (UnaryExpression) expression.Body; 
     var methodCallExpression = (MethodCallExpression) unaryExpression.Operand; 
     var methodInfoExpression = (ConstantExpression) methodCallExpression.Arguments.Last(); 
     var methodInfo = (MemberInfo) methodInfoExpression.Value; 
     return methodInfo; 
    } 

यह अपने लिए काम करता है इंटरफ़ेस, लेकिन शायद कुछ सामान्यीकरण को यह किसी भी विधि के साथ काम करने की आवश्यकता होगी, जो आपके ऊपर है।

+0

मैं कुछ कम वर्बोज़ की उम्मीद कर रहा था, लेकिन फिर भी, यह ठीक काम करता है, धन्यवाद। – Andre

+5

मैं उत्सुक हूं, और मुझे पता है कि यह 2 साल पहले की तरह है इसलिए मुझे उम्मीद है कि आप अभी भी जवाब दे सकते हैं: क्या इस तरह वाक्यविन्यास की अनुमति देने का कोई तरीका है: 'GetMethodInfo (x => x.DoSomething); '? – 9ee1

+2

इस दृष्टिकोण पर एक नोट, यह केवल .NET 3.5 और 4.0 में काम करता है, 4.5 में नहीं। बाद के मामले में, विधि कॉल अभिव्यक्ति का अलग-अलग प्रतिनिधित्व किया जाता है, और इसलिए पैरामीटर आदेश भिन्न होता है। उस स्थिति में आपको करना होगा: 'var methodInfoExpression = (ConstantExpression) methodCallExpression.Object; '। कुल मिलाकर मुझे यह दृष्टिकोण बहुत बोझिल लगता है। – nawfal

1

आपके आवेदन Moq पर निर्भरता (या किसी ऐसे ही पुस्तकालय), तो आप कुछ इस तरह कर सकता है की अनुमति होगी, तो:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var methodName = GetMethodName<IMyInteface>(x => new Action<string,string>(x.DoSomething)); 
     Console.WriteLine(methodName); 
    } 

    static string GetMethodName<T>(Func<T, Delegate> func) where T : class 
    { 
     // http://code.google.com/p/moq/ 
     var moq = new Mock<T>(); 
     var del = func.Invoke(moq.Object); 
     return del.Method.Name; 
    } 
} 

public interface IMyInteface 
{ 
    void DoSomething(string param1, string param2); 
} 
+1

-1, यह हैंडल देता है उस मध्यवर्ती अज्ञात प्रतिनिधि को जिसे आप बना रहे हैं ('GetMethodInfo' विधि को पास करने के लिए), वास्तविक सदस्य की नहीं, जिसे आप प्रस्तुत करने का प्रयास कर रहे हैं (' DoSomething')। – nawfal

+0

@nawful मूल पोस्टर ने स्ट्रिंग नाम के लिए पूछा, मूल विधिइन्फो नहीं। मैंने स्पष्ट करने के लिए अपना उदाहरण अपडेट किया है। – Wally

+0

मुझे चिंता है कि यह सही परिणाम अभी भी नहीं देता है। क्या आपने इसका परीक्षण किया है? – nawfal

4

इस समस्या के साथ समस्या यह है कि x.DoSomething एक विधि समूह का प्रतिनिधित्व करता है। और आपको किसी भी तरह से स्पष्ट रूप से निर्दिष्ट करना होगा कि आप किस विधि प्रकार को उस विधि समूह में परिवर्तित करना चाहते हैं, ताकि समूह के सही सदस्य का चयन किया जा सके। और इससे कोई फर्क नहीं पड़ता कि उस समूह में केवल एक सदस्य है।

कंपाइलर अनुमान लगा सकता है कि आप इसका मतलब है, लेकिन ऐसा नहीं करता है। (मुझे लगता है कि यह इस तरह से है कि यदि आप उस विधि का एक और अधिभार जोड़ते हैं तो आपका कोड तोड़ नहीं जाएगा।)

स्नोबियर के उत्तर में संभावित समाधानों पर अच्छी सलाह है।

+0

+1 वास्तविक समस्या का उल्लेख करने के लिए .. – nawfal

2

यह पुराने प्रश्न का एक नया उत्तर है, लेकिन स्वीकृत उत्तर की "verbose" शिकायत का जवाब देता है। इसे और अधिक कोड की आवश्यकता है, लेकिन परिणाम एक वाक्य रचना की तरह है:

MemberInfo info = GetActionInfo<IMyInterface, string, string>(x => x.DoSomething); 

या, एक वापसी मान

MemberInfo info = GetFuncInfo<IMyInterface, object, string, string>(x => x.DoSomethingWithReturn); 

जहां

object DoSomethingWithReturn(string param1, string param2); 

बस ढांचे की तरह कार्रवाई < प्रदान करता है साथ तरीकों के लिए > और Func <> 16 पैरामीटर तक प्रतिनिधि, आपको GetActionInfo और GetFuncInfo विधियों को प्राप्त करना होगा जो 16 पैरामीटर (या अधिक, को स्वीकार करते हैं, हालांकि मुझे लगता है कि रिफैक्टरिंग बुद्धिमान है यदि आपके पास 16 पैरामीटर के साथ विधियां हैं)। बहुत अधिक कोड, लेकिन वाक्यविन्यास में एक सुधार।

+1

मुझे उम्मीद है कि कम वर्बोज़ का मतलब है कि मैं ऐसा कुछ कर सकता हूं: 'GetMethodInfo (x => x.DoSomething); '? हालांकि मैं थोड़ा सा उलझन में हूं कि आपके सुझाव को कैसे कार्यान्वित किया जाए। क्या आप एक त्वरित कोड नमूना प्रदान कर सकते हैं? – 9ee1

+0

पैरामीटर को पार किए बिना इसे करने का एकमात्र तरीका (जिसे मैं जानता हूं) जेनेरिक विनिर्देश में पैरामीटर प्रकार शामिल करना है - i.e GetMethodInfo (x => x.DoSomething)। –

11

निम्नलिखित .NET 4.5 के साथ संगत है:

public static string MethodName(LambdaExpression expression) 
{ 
    var unaryExpression = (UnaryExpression)expression.Body; 
    var methodCallExpression = (MethodCallExpression)unaryExpression.Operand; 
    var methodCallObject = (ConstantExpression)methodCallExpression.Object; 
    var methodInfo = (MethodInfo)methodCallObject.Value; 

    return methodInfo.Name; 
} 

आप x => x.DoSomething की तरह भाव के साथ उपयोग कर सकते हैं लेकिन यह तरीकों के विभिन्न प्रकार के लिए सामान्य तरीकों में कुछ रैपिंग की आवश्यकता होगी।

private static bool IsNET45 = Type.GetType("System.Reflection.ReflectionContext", false) != null; 

public static string MethodName(LambdaExpression expression) 
{ 
    var unaryExpression = (UnaryExpression)expression.Body; 
    var methodCallExpression = (MethodCallExpression)unaryExpression.Operand; 
    if (IsNET45) 
    { 
     var methodCallObject = (ConstantExpression)methodCallExpression.Object; 
     var methodInfo = (MethodInfo)methodCallObject.Value; 
     return methodInfo.Name; 
    } 
    else 
    { 
     var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last(); 
     var methodInfo = (MemberInfo)methodInfoExpression.Value; 
     return methodInfo.Name; 
    } 
} 

चेक this sample code on Ideone:

यहाँ एक पीछे की ओर संगत संस्करण है। नोट, कि विचार में .NET 4.5 नहीं है।

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