c# - मैं विधि को कैसे ढूंढ सकता हूं जिसे वर्तमान विधि कहा जाता है?




.net logging (12)

सी # में लॉग इन करते समय, मैं उस विधि का नाम कैसे सीख सकता हूं जिसे वर्तमान विधि कहा जाता है? मैं System.Reflection.MethodBase.GetCurrentMethod() बारे में सब कुछ जानता हूं, लेकिन मैं स्टैक ट्रेस में इसके नीचे एक कदम जाना चाहता हूं। मैंने स्टैक ट्रेस को पार्सिंग पर विचार किया है, लेकिन मैं एक क्लीनर को अधिक स्पष्ट तरीके से ढूंढने की उम्मीद कर रहा हूं, जैसे Assembly.GetCallingAssembly() लेकिन विधियों के लिए।


आप कॉलर जानकारी और वैकल्पिक पैरामीटर का उपयोग कर सकते हैं:

public static string WhoseThere([CallerMemberName] string memberName = "")
{
       return memberName;
}

यह परीक्षण यह दिखाता है:

[Test]
public void Should_get_name_of_calling_method()
{
    var methodName = CachingHelpers.WhoseThere();
    Assert.That(methodName, Is.EqualTo("Should_get_name_of_calling_method"));
}

जबकि स्टैकट्रेस उपरोक्त तेजी से काम करता है और ज्यादातर मामलों में प्रदर्शन समस्या नहीं होगी, कॉलर जानकारी अभी भी बहुत तेज है। 1000 पुनरावृत्तियों के नमूने में, मैंने इसे 40 गुना तेज देखा।


इसे इस तरह से कॉल करने से, आपको पिछली विधियों को खींचने की अनुमति मिलती है, भले ही वह विधि किसी अन्य एप्लिकेशन से संबंधित हो।

    private enum METHOD_HISTORY
    {
        LAST_METHOD = 1,
        PREVIOUS_METHOD = 2
    }   //METHOD_HISTORY


    [MethodImpl(MethodImplOptions.NoInlining)]
    private string GetMethodName(METHOD_HISTORY lastMethod = METHOD_HISTORY.LAST_METHOD )
    {
        string retVal = "";

        StackTrace st = new StackTrace(new StackFrame((int)lastMethod));
        retVal = String.Format("{0}.{1}", st.GetFrame(0).GetMethod().ReflectedType.FullName, st.GetFrame(0).GetMethod().Name);

        return retVal;
    }

इसे कॉल करना:

string currentMethod = GetMethodName();

या

string prevtMethod = GetMethodName(METHOD_HISTORY.PREVIOUS_METHOD)

गति तुलना के साथ 2 दृष्टिकोणों का एक त्वरित पुनरावृत्ति महत्वपूर्ण हिस्सा है।

http://geekswithblogs.net/BlackRabbitCoder/archive/2013/07/25/c.net-little-wonders-getting-caller-information.aspx

संकलन समय पर कॉलर निर्धारित करना

static void Log(object message, 
[CallerMemberName] string memberName = "",
[CallerFilePath] string fileName = "",
[CallerLineNumber] int lineNumber = 0)
{
    // we'll just use a simple Console write for now    
    Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, memberName, message);
}

ढेर का उपयोग कर कॉलर निर्धारित करना

static void Log(object message)
{
    // frame 1, true for source info
    StackFrame frame = new StackFrame(1, true);
    var method = frame.GetMethod();
    var fileName = frame.GetFileName();
    var lineNumber = frame.GetFileLineNumber();

    // we'll just use a simple Console write for now    
    Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, method.Name, message);
}

2 दृष्टिकोण की तुलना

Time for 1,000,000 iterations with Attributes: 196 ms
Time for 1,000,000 iterations with StackTrace: 5096 ms

तो आप देखते हैं, विशेषताओं का उपयोग करना बहुत तेज़ है! वास्तव में लगभग 25x तेज।


जाहिर है यह एक देर का जवाब है, लेकिन यदि आप .NET 4.5 या अधिक का उपयोग कर सकते हैं तो मेरे पास एक बेहतर विकल्प है:

internal static void WriteInformation<T>(string text, [CallerMemberName]string method = "")
{
    Console.WriteLine(DateTime.Now.ToString() + " => " + typeof(T).FullName + "." + method + ": " + text);
}

यह वर्तमान दिनांक और समय को प्रिंट करेगा, इसके बाद "नेमस्पेस.क्लासनाम.माथनाम" और "टेक्स्ट" के साथ समाप्त होगा।
नमूना उत्पादन:

6/17/2016 12:41:49 PM => WpfApplication.MainWindow..ctor: MainWindow initialized

नमूना उपयोग:

Logger.WriteInformation<MainWindow>("MainWindow initialized");

मैंने जो अन्य दृष्टिकोण उपयोग किया है वह प्रश्न में विधि में पैरामीटर जोड़ना है। उदाहरण के लिए, void Foo() बजाय, void Foo(string context) । फिर कुछ अद्वितीय स्ट्रिंग में गुजरें जो कॉलिंग संदर्भ को इंगित करता है।

यदि आपको केवल विकास के लिए कॉलर / संदर्भ की आवश्यकता है, तो आप शिपिंग से पहले param को हटा सकते हैं।


शायद आप इस तरह कुछ ढूंढ रहे हैं:

StackFrame frame = new StackFrame(1);
frame.GetMethod().Name; //Gets the current method name

MethodBase method = frame.GetMethod();
method.DeclaringType.Name //Gets the current class name

सी # 5 में आप कॉलर जानकारी का उपयोग कर वह जानकारी प्राप्त कर सकते हैं:

//using System.Runtime.CompilerServices;
public void SendError(string Message, [CallerMemberName] string callerName = "") 
{ 
    Console.WriteLine(callerName + "called me."); 
} 

आप [CallerFilePath] और [CallerLineNumber] [CallerFilePath] भी प्राप्त कर सकते हैं।


हम कॉलर को खोजने के लिए लैम्ब्डा का भी उपयोग कर सकते हैं।

मान लीजिए कि आपके पास परिभाषित एक विधि है:

public void MethodA()
    {
        /*
         * Method code here
         */
    }

और आप इसे कॉलर ढूंढना चाहते हैं।

1 । विधि हस्ताक्षर बदलें ताकि हमारे पास प्रकार का पैरामीटर हो (Func भी काम करेगा):

public void MethodA(Action helperAction)
        {
            /*
             * Method code here
             */
        }

2 । Lambda नाम यादृच्छिक रूप से उत्पन्न नहीं होते हैं। नियम ऐसा लगता है:> <CallerMethodName> __ एक्स जहां कॉलर मोडिंगनाम को पिछले फ़ंक्शन द्वारा प्रतिस्थापित किया गया है और एक्स एक अनुक्रमणिका है।

private MethodInfo GetCallingMethodInfo(string funcName)
    {
        return GetType().GetMethod(
              funcName.Substring(1,
                                funcName.IndexOf("&gt;", 1, StringComparison.Ordinal) - 1)
              );
    }

3 । जब हम विधि ए कॉल करते हैं तो कॉलर विधि द्वारा एक्शन / फनक पैरामीटर उत्पन्न किया जाना चाहिए। उदाहरण:

MethodA(() => {});

4 । विधि ए के अंदर हम अब ऊपर परिभाषित सहायक कार्य को कॉल कर सकते हैं और कॉलर विधि के MethodInfo को ढूंढ सकते हैं।

उदाहरण:

MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name);

.NET 4.5 के रूप में आप कॉलर सूचना विशेषताओं का उपयोग कर सकते हैं:

  • CallerFilePath - स्रोत फ़ाइल जिसे फ़ंक्शन कहा जाता है;
  • CallerLineNumber - कोड की रेखा जिसे फ़ंक्शन कहा जाता है;
  • CallerMemberName - सदस्य जिसे फ़ंक्शन कहा जाता है।

    public void WriteLine(
        [CallerFilePath] string callerFilePath = "", 
        [CallerLineNumber] long callerLineNumber = 0,
        [CallerMemberName] string callerMember= "")
    {
        Debug.WriteLine(
            "Caller File Path: {0}, Caller Line Number: {1}, Caller Member: {2}", 
            callerFilePath,
            callerLineNumber,
            callerMember);
    }
    

यह सुविधा ".NET कोर" और ".NET मानक" में भी मौजूद है।

संदर्भ

  1. माइक्रोसॉफ्ट - कॉलर सूचना (सी #)
  2. CallerFilePath
  3. CallerLineNumber
  4. CallerMemberName

.NET में लॉगिंग विधि नाम पर एक नज़र डालें। उत्पादन कोड में इसका उपयोग करने से सावधान रहें। StackFrame भरोसेमंद नहीं हो सकता है ...


StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1);
string methodName = caller.GetMethod().Name;

पर्याप्त होगा, मुझे लगता है।


private static MethodBase GetCallingMethod()
{
  return new StackFrame(2, false).GetMethod();
}

private static Type GetCallingType()
{
  return new StackFrame(2, false).GetMethod().DeclaringType;
}

एक शानदार वर्ग यहां है: http://www.csharp411.com/c-get-calling-method/






system.diagnostics