当前位置:  开发笔记 > 大数据 > 正文

你能用反射来找到当前正在执行的方法的名称吗?

如何解决《你能用反射来找到当前正在执行的方法的名称吗?》经验,为你挑选了8个好方法。

就像标题所说:反射可以为您提供当前正在执行的方法的名称.

由于海森堡的问题,我倾向于不猜.如何在不改变当前方法的情况下调用一种方法来告诉您当前的方法?但是我希望有人可以在那里证明我的错.

更新:

第2部分:这可以用来查看属性的内部代码吗?

第3部分:性能如何?

最终结果
我了解了MethodBase.GetCurrentMethod().我还了解到,我不仅可以创建堆栈跟踪,而且如果需要,我只能创建我需要的确切帧.

要在属性中使用它,只需使用.Substring(4)删除'set_'或'get_'.



1> Ed Guiness..:
System.Reflection.MethodBase.GetCurrentMethod().Name;

http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx


请注意,这并不总能产生预期的结果.即,在发布版本中经常内联小方法或属性,在这种情况下,结果将是调用方的方法名称.
据我所知,没有.因为在运行时,MSIL不再可用于执行指针(它是JITted).如果您知道方法的名称,仍然可以使用反射.关键是,当内联时,当前正在执行的方法现在是另一种方法(即,堆栈中的一个或多个更高).换句话说,该方法消失了.即使你用NoInlining标记你的方法,它仍然有可能被尾部调用优化,在这种情况下它也消失了.但是,在调试版本中,它可以工作.

2> John Nilsson..:

从.NET 4.5开始,您还可以使用[CallerMemberName]

示例:属性设置器(回答第2部分):

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

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

编译器将在callites中提供匹配的字符串文字,因此基本上没有性能开销.


[CallerMemberName]在网络4上有效[BCL build packed](http://www.nuget.org/packages/Microsoft.Bcl/1.0.19)
这很棒!我正在使用其他答案中描述的`StackFrame(1)`方法进行日志记录,这似乎一直有效,直到Jitter决定开始内联.我不想添加属性以防止出于性能原因进行内联.使用`[CallerMemberName]`方法解决了这个问题.谢谢!
考虑在调试模式下使用StackFrame(1)应该可行.但是在编译时使用发布模式时,可能会有一些优化,而堆栈可能不是您所期望的.

3> Joel Coehoor..:

Lex提供的片段有点长,所以我指出了重要的部分,因为没有其他人使用完全相同的技术:

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

这应该返回相同的结果到MethodBase.GetCurrentMethod().名称技术,但它仍然值得指出,因为我可以在它自己的方法中使用索引1为前一个方法实现这一次,并从许多不同的属性调用它.此外,它只返回一帧而不是整个堆栈跟踪:

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

这也是一个单行;)


同埃德吉尼斯的回答是:堆栈可以在不同的版本构建和第一种方法可能不是相同的内联或尾调用优化的情况下,当前方法.

4> Lars Mæhlum..:

在空控制台程序中的Main方法中尝试:

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

控制台输出:
Main



5> Lex..:

当然是.

如果你想要一个对象操作我实际上使用这样的函数:

public static T CreateWrapper(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支持的解决方案,之前您在事件代码中遍布了所有字符串.



6> drzaus..:

比较获取方法名称的方法 - 在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 /sf/ask/17360801/

    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> ex = e => e.expr();
        return ex.ToString();
    }
    public string exprmember() {
        return expressionName(e => e.exprmember);
    }
    protected string expressionName(Expression>> action) {
        // /sf/ask/17360801/
        return ((((action.Body as UnaryExpression).Operand as MethodCallExpression).Object as ConstantExpression).Value as MethodInfo).Name;
    }
    public string callermember([CallerMemberName]string name = null) {
        return name;
    }
}

结果

反射 反射

stacktrace stacktrace

inlineconstant inlineconstant

恒定 不变

expr e => e.expr()

exprmember exprmember

来电成员 主要

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

请注意,exprcallermember方法并不完全"正确".在那里你看到一个相关评论的重复,反射比堆栈跟踪快〜15倍.



7> denis philli..:

编辑: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)]



8> 小智..:

处理的简单方法是:

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

如果System.Reflection包含在using块中:

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

推荐阅读
ar_wen2402851455
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有