就像标题所说:反射可以为您提供当前正在执行的方法的名称.
由于海森堡的问题,我倾向于不猜.如何在不改变当前方法的情况下调用一种方法来告诉您当前的方法?但是我希望有人可以在那里证明我的错.
更新:
第2部分:这可以用来查看属性的内部代码吗?
第3部分:性能如何?
最终结果
我了解了MethodBase.GetCurrentMethod().我还了解到,我不仅可以创建堆栈跟踪,而且如果需要,我只能创建我需要的确切帧.
要在属性中使用它,只需使用.Substring(4)删除'set_'或'get_'.
System.Reflection.MethodBase.GetCurrentMethod().Name;
http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getcurrentmethod.aspx
从.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中提供匹配的字符串文字,因此基本上没有性能开销.
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); }
这也是一个单行;)
在空控制台程序中的Main方法中尝试:
MethodBase method = MethodBase.GetCurrentMethod(); Console.WriteLine(method.Name);
控制台输出:
Main
当然是.
如果你想要一个对象操作我实际上使用这样的函数:
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支持的解决方案,之前您在事件代码中遍布了所有字符串.
比较获取方法名称的方法 - 在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
请注意,expr
和callermember
方法并不完全"正确".在那里你看到一个相关评论的重复,反射比堆栈跟踪快〜15倍.
编辑: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)]
处理的简单方法是:
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + System.Reflection.MethodBase.GetCurrentMethod().Name;
如果System.Reflection包含在using块中:
MethodBase.GetCurrentMethod().DeclaringType.FullName + "." + MethodBase.GetCurrentMethod().Name;