2013-11-23 32 views
15

async関数の中から現在のメソッド名を取得する方法はありますか?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 "、" Invoke "、" CreateInstance "、" CreateKnownObject "または" CreateUnknownObject "または" MoveNext "

どのように私はこれを行うことができますか?私はジェネリックロガー関数を作成したいと思いますし、ロガー関数を呼び出した関数の名前を渡したくないので、stacktraceメソッドを試してみました。うまくいきませんでした。

私はあきらめて、関数名を最初のパラメータとして渡しますが、汎用のロガー関数を呼び出す呼び出し関数からリフレクションメソッドを呼び出すと、私は常に "を取得します。 ctor "

アイデア?私が呼び出すジェネリック・ロガー関数は、同じクラスの静的メソッドであることに注意してください(これは今のところこのようにしなければなりません...)。

+0

P.S. [EventSource> P/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

C#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

残念ながら、今はC#5.0に対してコンパイルできません(ただし、 )。 他の解決策がありますか? – user2939634

+0

@ user2939634どのように 'async'でコンパイルしていますか? .Net 4.0にAsyncターゲティングパックを使用していますか?もしそうなら、 'System.Runtime.CompilerServices'名前空間に独自の属性' CallerMemberName'を定義することができます。これは(別の答えにコメントで言及されたように)うまくいくはずです。 –

+1

呼び出し元情報属性を使用してメソッド名を取得することは、例外が発生した呼び出しスタック内の最初のメソッドを取得できないため、グローバルエラーロガーでは役に立ちません。 [CallerMemberName]は、グローバルエラーハンドラを呼び出したメソッドの名前のみを取得します。 –

6

リリースビルドではいくつかの方法が最適化される可能性があるため、高価で危険な手動スタックフレームウォークを行うのではなく、Caller Information属性の1つ(CallerMemberNameAttribute)を.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の機能ではなく、C#5.0の機能です。 C#5.0を使用して.Net 4.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

あなたはSystem.Reflection.MethodBase.DeclaringType.FullNameが<>文字があり、場合かどうかを確認する機能にSystem.Reflection.MethodBaseオブジェクトであるstrackTrace.GetFrame(I).GetMethodを()送信することができます< ...> charsの間にある要求されたメソッド名を取得します。

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

この方法は、非同期メソッド呼び出しからだけでなく、通常の方法で動作します。 (C#5)

/// <summary> 
///  Returns Current method name 
/// </summary> 
/// <returns>callers method name</returns> 
public string GetCurrentMethod([CallerMemberName] string callerName = "") 
{ 
    return callerName; 
} 
関連する問題