2013-11-23 12 views
15

क्या एसिंक फ़ंक्शन के अंदर से वर्तमान विधि नाम प्राप्त करने के लिए वैसे भी है?async फ़ंक्शन से वर्तमान विधि का नाम प्राप्त करें?

मैं कोशिश की है:

System.Reflection.MethodInfo.GetCurrentMethod(); 

और मैं StackTrace और StrackFrame का उपयोग कर के रूप में इस की कोशिश की है:

StackTrace strackTrace = new StackTrace(); 

for (int i = 0; i < strackTrace.GetFrames().Length; i++) 
{ 
    SafeNativeMethods.EtwTraceInfo("Function" + i + ":" + function); 
    SafeNativeMethods.EtwTraceInfo("Type" + i + ":" + strackTrace.GetFrame(i).GetType().Name); 
    SafeNativeMethods.EtwTraceInfo("Method" + i + ":" + strackTrace.GetFrame(i).GetMethod().Name); 
    SafeNativeMethods.EtwTraceInfo("ToString Call" + i + ":" + strackTrace.GetFrame(i).ToString()); 
} 

लेकिन उनमें से कोई भी काम करने के लिए लगता है, मैं ".ctor प्राप्त होता "," InvokeMethod "," Invocstance "," CreateInnownObject "," CreateKnownObject "या" CreateUnknownObject "या" MoveNext "

कोई विचार यह है कि मैं यह कैसे कर सकता हूं? मैं एक जेनेरिक लॉगर फ़ंक्शन बनाना चाहता हूं और मैं फ़ंक्शन के नाम पर पास नहीं करना चाहता हूं जिसे लॉगर फ़ंक्शन कहा जाता है, इसलिए मैंने स्टैकट्रैस विधि की कोशिश की, काम नहीं किया।

मैं उस पर छोड़ दिया और कहा, ठीक है, मैं पहले पैरामीटर के रूप समारोह के नाम पर पास भेज देंगे, लेकिन जब मैं बुला समारोह सामान्य लकड़हारा फ़ंक्शन को कॉल करने से प्रतिबिंब विधि कहा जाता है, मैं हमेशा मिलता है "। सीटीओआर "

कोई विचार? ध्यान दें कि जेनेरिक लॉगर फ़ंक्शन जिसे मैं कॉल कर रहा हूं वह एक ही कक्षा में एक स्थिर विधि है (इसे अभी इस तरह से होना चाहिए ...)।

+0

पीएस [EventSource> पी/Invoke] (http://blogs.msdn.com/b/vancem/archive/tags/eventsource/) –

उत्तर

0

आपको पहले एसिंक कॉल से पहले कहीं भी एसिंक विधि में विधि नाम कैप्चर करने की आवश्यकता है। संकलक उत्पन्न राज्य मशीन के पीछे छोड़ने का सबसे सुविधाजनक तरीका स्टैक ट्रेस में प्रत्येक विधि के घोषित प्रकार को देखना है।

var method = new StackTrace() 
    .GetFrames() 
    .Select(frame => frame.GetMethod()) 
    .FirstOrDefault(item => item.DeclaringType == GetType()); 
await Task.Yield(); 
if (method != null) 
{ 
    Console.WriteLine(method.Name); 
} 
13

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

CallerMemberNameAttribute का उपयोग कर एक उदाहरण:

using System.Runtime.CompilerServices; 

public static void Main(string[] args) 
{ 
    Test().Wait();    
} 

private static async Task Test() 
{ 
    await Task.Yield(); 
    Log(); 
    await Task.Yield(); 
} 

private static void Log([CallerMemberName]string name = "") 
{ 
    Console.WriteLine("Log: {0}", name); 
} 

CallerFilePath और CallerLineNumber जिम्मेदार बताते हैं, जिस पर कॉल साइट के बारे में जानकारी के अन्य टुकड़े प्राप्त कर सकते हैं भी कर रहे हैं।

+0

दुर्भाग्यवश मैं अभी सी # 5.0 के खिलाफ संकलित नहीं कर सकता (हालांकि मैं उस पर दोबारा जांच करूंगा)। क्या कोई अन्य समाधान है जो ध्यान में आता है? – user2939634

+0

@ user2939634 फिर आप 'async' के साथ कैसे संकलित कर रहे हैं? क्या आप .NET 4.0 के लिए Async लक्ष्यीकरण पैक का उपयोग कर रहे हैं? यदि ऐसा है, तो आप 'System.Runtime.CompilerServices' नेमस्पेस' में अपनी खुद की विशेषता 'CallerMemberName' को परिभाषित कर सकते हैं और इसे काम करना चाहिए (जैसा कि अन्य शब्दों में टिप्पणियों में उल्लिखित है)। –

+1

कॉलर जानकारी विशेषताओं का उपयोग करके विधि का नाम प्राप्त करना वैश्विक त्रुटि लॉगर में बेकार है क्योंकि आपको कॉल स्टैक में पहली विधि नहीं मिल सकती है जहां अपवाद उठाया गया था। [कॉलरमेम्बरनाम] केवल उस विधि का नाम प्राप्त करता है जिसे वैश्विक त्रुटि हैंडलर कहा जाता है। –

6

मैनुअल स्टैक फ्रेम कर चलता बजाय, जो दोनों महंगा और जोखिम भरा है (के बाद से रिलीज बनाता है कुछ तरीकों बाहर का अनुकूलन कर सकते हैं), तो आपको CallerMemberNameAttribute, Caller Information गुण है, जो .NET 4.5 में जोड़ा गया है में से एक का उपयोग कर सकते हैं (जो इस सटीक परिदृश्य के लिए आप पहले से ही उपयोग करते हैं, अगर आप async/await का उपयोग करते हैं) - लॉगर्स, संपत्ति-बदले हैंडलर और इसी तरह के सदस्य नाम में गुजरना।

यह इस प्रकार है:

public void LogMessage(string message, [CallerMemberName] string caller = "") 
{ 
    // caller should contain the name of the method that called LogMessage. 
} 

मैं किसी भी सीमा इस async तरीकों के साथ है का पता नहीं है।

+0

कॉलर सदस्य विशेषताएँ वास्तव में .NET 4.5 की एक विशेषता नहीं हैं, वे सी # 5.0 की एक विशेषता हैं। यदि आप नेट 4.0 को लक्षित करने के लिए सी # 5.0 का उपयोग कर रहे हैं, तो आप उस विशेषता को स्वयं परिभाषित कर सकते हैं और यह काम करेगा। – svick

+0

@svick क्या आप एक उदाहरण पोस्ट कर सकते हैं या हमें एक लिंक दे सकते हैं? –

+1

@StefanVasiljevic [यह कोड] (https://gist.github.com/svick/97c6a8c8b006283c96e2) मेरे लिए काम करता है। – svick

0

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

  1. परिभाषित निम्नलिखित Regex कहीं कि सभी कॉल द्वारा पहुँचा जा सकता क्योंकि Regex वस्तुओं उन्हें प्रयोग करने से पहले पार्स किया जा सकता की जरूरत है; इसलिए, यह महंगा हो सकता है, और यदि हम इसका उपयोग कर सकते हैं तो उन्हें बनाने के लिए एक अच्छा अभ्यास नहीं है।
    public static readonly Regex ASYNC_METHOD_NAME_FORMAT = new Regex(@"^\<(?\w+)>\w+?");
  2. विधि नाम
    string methodName = ASYNC_METHOD_NAME_FORMAT.Match(MethodBase.GetCurrentMethod().ReflectedType.Name).Groups["method_name"].Value

मुझे आशा है कि इस मदद करता है पाने के लिए निम्न कोड का प्रयोग करें!

0

आप strackTrace.GetFrame (i) .GetMethod() जो एक समारोह की जाँच करता है कि अगर System.Reflection.MethodBase.DeclaringType.FullName <> वर्ण है और अगर करने के लिए एक System.Reflection.MethodBase वस्तु है भेज सकते हैं इसलिए अनुरोध किया गया विधि नाम मिलेगा जो < ...> वर्णों के बीच रहता है।

static private string getMethodName(System.Reflection.MethodBase method) 
    { 
     string _methodName = method.DeclaringType.FullName; 

     if (_methodName.Contains(">") || _methodName.Contains("<")) 
     { 
      _methodName = _methodName.Split('<', '>')[1]; 
     } 
     else 
     { 
      _methodName = method.Name; 
     } 

     return _methodName; 
    } 

और कैसे उदाहरण का उपयोग करने के लिए है:

var _stackTrace = new System.Diagnostics.StackTrace(exception, true); 
string _methodName = getMethodName(_stackTrace.GetFrame(0).GetMethod()); 
4

इस विधि से async विधि कॉल के साथ ही सामान्य विधि से काम करता है। (सी # 5)

/// <summary> 
///  Returns Current method name 
/// </summary> 
/// <returns>callers method name</returns> 
public string GetCurrentMethod([CallerMemberName] string callerName = "") 
{ 
    return callerName; 
} 
संबंधित मुद्दे