211

タイトルが言うように: リフレクションは現在実行中のメソッドの名前を教えてくれますか?

ハイゼンベルグ問題のため、私はそうではないと推測する傾向があります。現在のメソッドが何であるかを変更せずに、現在のメソッドを通知するメソッドを呼び出すにはどうすればよいでしょうか? しかし、誰かが私が間違っていることを証明してくれることを願っています。

アップデート:

  • パート 2: これを使用して、プロパティのコード内を調べることもできますか?
  • パート3:パフォーマンスはどうなる?

最終結果
MethodBase.GetCurrentMethod() について学びました。また、スタック トレースを作成できるだけでなく、必要に応じて必要なフレームだけを作成できることも学びました。

これをプロパティ内で使用するには、.Substring(4) を使用して「set_」または「get_」を削除します。

4

18 に答える 18

191

asyncメソッドの場合、使用できます

System.Reflection.MethodBase.GetCurrentMethod().Name;

https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.getcurrentmethod

asyncメソッドの場合、「MoveNext」が返されることに注意してください。

于 2008-09-04T16:51:11.363 に答える
129

.NET 4.5以降では、 [CallerMemberName]も使用できます。

例:プロパティセッター(パート2に回答するため):

protected void SetProperty<T>(T value, [CallerMemberName] string property = null)
{
    this.propertyValues[property] = value;
    OnPropertyChanged(property);
}

public string SomeProperty
{
    set { SetProperty(value); }
}

コンパイラは呼び出しサイトで一致する文字列リテラルを提供するため、基本的にパフォーマンスのオーバーヘッドはありません。

于 2013-03-09T11:18:17.030 に答える
48

Lex によって提供されたスニペットは少し長いので、まったく同じ手法を使用した人は他にいないため、重要な部分を指摘します。

string MethodName = new StackFrame(0).GetMethod().Name;

これはMethodBase.GetCurrentMethod().Name手法と同じ結果を返すはずですが、のメソッドのインデックス 1 を使用して独自のメソッドにこれを一度実装し、さまざまなプロパティから呼び出すことができるため、指摘する価値があります。また、スタック トレース全体ではなく、1 つのフレームのみを返します。

private string GetPropertyName()
{  //.SubString(4) strips the property prefix (get|set) from the name
    return new StackFrame(1).GetMethod().Name.Substring(4);
}

それもワンライナーです;)

于 2008-09-04T17:18:09.660 に答える
18

空のコンソール プログラムの Main メソッド内でこれを試してください。

MethodBase method = MethodBase.GetCurrentMethod();
Console.WriteLine(method.Name);

コンソール出力:
Main

于 2008-09-04T16:52:03.640 に答える
13

メソッド名を取得する方法の比較 - LinqPad で任意のタイミング構造を使用:

コード

void Main()
{
    // from http://blogs.msdn.com/b/webdevelopertips/archive/2009/06/23/tip-83-did-you-know-you-can-get-the-name-of-the-calling-method-from-the-stack-using-reflection.aspx
    // and https://stackoverflow.com/questions/2652460/c-sharp-how-to-get-the-name-of-the-current-method-from-code

    var fn = new methods();

    fn.reflection().Dump("reflection");
    fn.stacktrace().Dump("stacktrace");
    fn.inlineconstant().Dump("inlineconstant");
    fn.constant().Dump("constant");
    fn.expr().Dump("expr");
    fn.exprmember().Dump("exprmember");
    fn.callermember().Dump("callermember");

    new Perf {
        { "reflection", n => fn.reflection() },
        { "stacktrace", n => fn.stacktrace() },
        { "inlineconstant", n => fn.inlineconstant() },
        { "constant", n => fn.constant() },
        { "expr", n => fn.expr() },
        { "exprmember", n => fn.exprmember() },
        { "callermember", n => fn.callermember() },
    }.Vs("Method name retrieval");
}

// Define other methods and classes here
class methods {
    public string reflection() {
        return System.Reflection.MethodBase.GetCurrentMethod().Name;
    }
    public string stacktrace() {
        return new StackTrace().GetFrame(0).GetMethod().Name;
    }
    public string inlineconstant() {
        return "inlineconstant";
    }
    const string CONSTANT_NAME = "constant";
    public string constant() {
        return CONSTANT_NAME;
    }
    public string expr() {
        Expression<Func<methods, string>> ex = e => e.expr();
        return ex.ToString();
    }
    public string exprmember() {
        return expressionName<methods,string>(e => e.exprmember);
    }
    protected string expressionName<T,P>(Expression<Func<T,Func<P>>> action) {
        // https://stackoverflow.com/a/9015598/1037948
        return ((((action.Body as UnaryExpression).Operand as MethodCallExpression).Object as ConstantExpression).Value as MethodInfo).Name;
    }
    public string callermember([CallerMemberName]string name = null) {
        return name;
    }
}

結果

リフレクション _

スタック トレース

インライン定数インライン 定数

定数 定数

expr e => e.expr()

exprmember exprmember

callermember メイン

Method name retrieval: (reflection) vs (stacktrace) vs (inlineconstant) vs (constant) vs (expr) vs (exprmember) vs (callermember) 

 154673 ticks elapsed ( 15.4673 ms) - reflection
2588601 ticks elapsed (258.8601 ms) - stacktrace
   1985 ticks elapsed (  0.1985 ms) - inlineconstant
   1385 ticks elapsed (  0.1385 ms) - constant
1366706 ticks elapsed (136.6706 ms) - expr
 775160 ticks elapsed ( 77.516  ms) - exprmember
   2073 ticks elapsed (  0.2073 ms) - callermember


>> winner: constant

exprおよびcallermemberメソッドは完全に「正しい」わけではないことに注意してください。そこには、リフレクションがスタックトレースよりも ~15 倍高速であるという関連コメントが繰り返し表示されています。

于 2014-01-22T22:34:21.763 に答える
12

はい、間違いなく。

オブジェクトを操作したい場合は、実際に次のような関数を使用します。

public static T CreateWrapper<T>(Exception innerException, params object[] parameterValues) where T : Exception, new()
{
    if (parameterValues == null)
    {
        parameterValues = new object[0];
    }

    Exception exception   = null;
    StringBuilder builder = new StringBuilder();
    MethodBase method     = new StackFrame(2).GetMethod();
    ParameterInfo[] parameters = method.GetParameters();
    builder.AppendFormat(CultureInfo.InvariantCulture, ExceptionFormat, new object[] { method.DeclaringType.Name, method.Name });
    if ((parameters.Length > 0) || (parameterValues.Length > 0))
    {
        builder.Append(GetParameterList(parameters, parameterValues));
    }

    exception = (Exception)Activator.CreateInstance(typeof(T), new object[] { builder.ToString(), innerException });
    return (T)exception;
}

この行:

MethodBase method     = new StackFrame(2).GetMethod();

スタック フレームを調べて呼び出し元のメソッドを見つけ、リフレクションを使用して、一般的なエラー レポート関数用に渡されたパラメーター情報の値を取得します。現在のメソッドを取得するには、代わりに現在のスタック フレーム (1) を使用します。

現在のメソッド名について他の人が言っているように、次のものも使用できます。

MethodBase.GetCurrentMethod()

そのメソッドを内部的に見ると、とにかく StackCrawlMark を作成するだけなので、スタックを歩くことを好みます。スタックに直接アドレス指定する方が明確に思えます

Post 4.5 では、[CallerMemberNameAttribute] をメソッド パラメータの一部として使用して、メソッド名の文字列を取得できるようになりました。これは、いくつかのシナリオで役立つ場合があります (ただし、実際には上記の例で言えば)。

public void Foo ([CallerMemberName] string methodName = null)

これは主に、以前はイベント コード全体に文字列が散らばっていた INotifyPropertyChanged サポートのソリューションのようです。

于 2008-09-04T16:50:58.243 に答える
9

編集: MethodBase は、(呼び出しスタック全体とは対照的に) 現在のメソッドを取得するためのおそらくより良い方法です。ただし、インライン化についてはまだ心配です。

メソッド内で StackTrace を使用できます。

StackTrace st = new StackTrace(true);

そして、フレームを見てください:

// The first frame will be the method you want (However, see caution below)
st.GetFrames();

ただし、メソッドがインライン化されている場合は、自分がいると思っているメソッドの中にいないことに注意してください。属性を使用してインライン化を防ぐことができます。

[MethodImpl(MethodImplOptions.NoInlining)]
于 2008-09-04T16:52:40.440 に答える
8

対処する簡単な方法は次のとおりです。

System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + System.Reflection.MethodBase.GetCurrentMethod().Name;

System.Reflection が using ブロックに含まれている場合:

MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + MethodBase.GetCurrentMethod().Name;
于 2015-10-08T15:50:46.617 に答える
4

これはどう:

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
于 2008-10-05T20:11:13.670 に答える
2

StackTraceを作成することでそれを取得できるはずだと思います。または、@ edgと @ Lars Mæhlumが言及しているように、MethodBase. GetCurrentMethod ()

于 2008-09-04T16:48:10.777 に答える