How can I find the method that called the current method?
当登录C时,我如何才能了解调用当前方法的方法的名称?我对
试试这个:
1 2 3 4 5 6 | using System.Diagnostics; // Get call stack StackTrace stackTrace = new StackTrace(); // Get calling method name Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name); |
它来自使用反射的get调用方法。
在C 5中,您可以使用呼叫者信息获取该信息:
1 2 3 4 5 | //using System.Runtime.CompilerServices; public void SendError(string Message, [CallerMemberName] string callerName ="") { Console.WriteLine(callerName +"called me."); } |
你也可以得到
您可以使用呼叫者信息和可选参数:
1 2 3 4 | public static string WhoseThere([CallerMemberName] string memberName ="") { return memberName; } |
此测试说明了这一点:
1 2 3 4 5 6 | [Test] public void Should_get_name_of_calling_method() { var methodName = CachingHelpers.WhoseThere(); Assert.That(methodName, Is.EqualTo("Should_get_name_of_calling_method")); } |
虽然stacktrace在上面工作得很快,在大多数情况下不会成为性能问题,但调用方信息仍然要快得多。在一个1000次迭代的样本中,我把它的速度提高了40倍。
一般来说,可以使用
(注:我只是在扩展Firas Assad提供的答案。)
我们可以通过只实例化我们实际需要的帧(而不是整个堆栈),稍微改进一下阿萨德先生的代码(当前接受的答案):
1 |
这可能会更好一点,尽管很可能它仍然需要使用完整的堆栈来创建那个单帧。此外,它仍然有亚历克斯莱曼指出的同样的警告(优化器/本机代码可能会破坏结果)。最后,您可能希望检查以确保
请参阅此相关问题:可以使用反射来查找当前执行方法的名称吗?
快速回顾两种方法,其中速度比较是重要的部分。
http://geekswithblogs.net/blackrabbitcoder/archive/2013/07/25/c.net-little-wounds-getting-caller-information.aspx
在编译时确定调用方
1 2 3 4 5 6 7 8 | 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); } |
使用堆栈确定调用方
1 2 3 4 5 6 7 8 9 10 11 | 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); } |
两种方法的比较
1 2 | Time for 1,000,000 iterations with Attributes: 196 ms Time for 1,000,000 iterations with StackTrace: 5096 ms |
So you see, using the attributes is much, much faster! Nearly 25x
faster in fact.
从.NET 4.5开始,您可以使用调用方信息属性:
CallerFilePath —调用函数的源文件;CallerLineNumber —调用函数的代码行;CallerMemberName —调用函数的成员。1
2
3
4
5
6
7
8
9
10
11public 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);
}
nbsp;
此工具也存在于".net core"和".net standard"中。
工具书类
注意,由于优化,这样做在发布代码中是不可靠的。此外,以沙盒模式(网络共享)运行应用程序根本不允许您获取堆栈帧。
考虑面向方面编程(AOP),比如PostSharp,它不是从代码中调用的,而是修改代码,从而随时知道代码在哪里。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /// <summary> /// Returns the call that occurred just before the"GetCallingMethod". /// </summary> public static string GetCallingMethod() { return GetCallingMethod("GetCallingMethod"); } /// <summary> /// Returns the call that occurred just before the the method specified. /// </summary> /// <param name="MethodAfter">The named method to see what happened just before it was called. (case sensitive)</param> /// <returns>The method name.</returns> public static string GetCallingMethod(string MethodAfter) { string str =""; try { StackTrace st = new StackTrace(); StackFrame[] frames = st.GetFrames(); for (int i = 0; i < st.FrameCount - 1; i++) { if (frames[i].GetMethod().Name.Equals(MethodAfter)) { if (!frames[i + 1].GetMethod().Name.Equals(MethodAfter)) // ignores overloaded methods. { str = frames[i + 1].GetMethod().ReflectedType.FullName +"." + frames[i + 1].GetMethod().Name; break; } } } } catch (Exception) { ; } return str; } |
显然这是一个迟来的答案,但如果您可以使用.NET 4.5或更高版本,我有更好的选择:
1 2 3 4 | internal static void WriteInformation<T>(string text, [CallerMemberName]string method ="") { Console.WriteLine(DateTime.Now.ToString() +" =>" + typeof(T).FullName +"." + method +":" + text); } |
这将打印当前日期和时间,后跟"namespace.classname.methodname",并以":text"结尾。样品输出:
1 | 6/17/2016 12:41:49 PM => WpfApplication.MainWindow..ctor: MainWindow initialized |
样品使用:
1 | Logger.WriteInformation<MainWindow>("MainWindow initialized"); |
也许你在找这样的东西:
1 2 3 4 5 | 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 |
1 2 3 4 5 6 7 8 9 |
这里有一个很棒的课程:http://www.csharp411.com/c-get-calling-method/
我使用的另一种方法是向所讨论的方法添加参数。例如,使用
如果您只需要调用方/上下文进行开发,那么可以在发货前删除
1 2 | StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1); string methodName = caller.GetMethod().Name; |
我想就够了。
我们也可以使用lambda来查找调用方。
假设您定义了一个方法:
1 2 3 4 5 6 | public void MethodA() { /* * Method code here */ } |
你想找到打电话的人。
1。更改方法签名,使我们有一个action类型的参数(func也可以工作):
1 2 3 4 5 6 | public void MethodA(Action helperAction) { /* * Method code here */ } |
2。lambda名称不是随机生成的。规则似乎是:>
1 2 3 4 5 6 7 | private MethodInfo GetCallingMethodInfo(string funcName) { return GetType().GetMethod( funcName.Substring(1, funcName.IndexOf(">", 1, StringComparison.Ordinal) - 1) ); } |
三。当我们调用methoda时,action/func参数必须由调用方方法生成。例子:
1 | MethodA(() => {}); |
4。在methoda中,我们现在可以调用上面定义的helper函数并找到调用方方法的methodinfo。
例子:
1 | MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name); |
看看.NET中的日志方法名。小心在生产代码中使用它。StackFrame可能不可靠…
要获取方法名和类名,请尝试以下操作:
1 2 3 4 5 6 7 8 9 | public static void Call() { StackTrace stackTrace = new StackTrace(); var methodName = stackTrace.GetFrame(1).GetMethod(); var className = methodName.DeclaringType.Name.ToString(); Console.WriteLine(methodName.Name +"*****" + className ); } |
Firas Assaad回答的额外信息。
我在.NET核心2.1中使用了
我试过用EDOCX1[1]它给了我正确的调用方法
1 2 | var callingMethod = new StackFrame(1, true).GetMethod(); string source = callingMethod.ReflectedType.FullName +":" + callingMethod.Name; |