我怎样才能find调用当前方法的方法?
在C#中login时,如何才能知道调用当前方法的方法的名称? 我知道所有关于System.Reflection.MethodBase.GetCurrentMethod()
,但我想在堆栈跟踪下的这一步。 我已经考虑parsing堆栈跟踪,但我希望find一个更清晰的方法,像Assembly.GetCallingAssembly()
但方法。
尝试这个:
using System.Diagnostics; // Get call stack StackTrace stackTrace = new StackTrace(); // Get calling method name Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);
它来自使用reflection[C#]获取调用方法 。
在C#5中,您可以使用调用者信息获取该信息:
//using System.Runtime.CompilerServices; public void SendError(string Message, [CallerMemberName] string callerName = "") { Console.WriteLine(callerName + "called me."); }
你也可以得到[CallerFilePath]
和[CallerLineNumber]
。
您可以使用来电者信息和可选参数:
public static string WhoseThere([CallerMemberName] string memberName = "") { return memberName; }
这个testing说明了这个:
[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倍。
通常,您可以使用System.Diagnostics.StackTrace
类来获取System.Diagnostics.StackFrame
,然后使用GetMethod()
方法来获取System.Reflection.MethodBase
对象。 但是,这种方法有一些注意事项 :
- 它表示运行时堆栈 – 优化可以内联一个方法,并且不会在堆栈跟踪中看到该方法。
- 它不会显示任何本地框架,所以如果有一个偶然的机会被一个本地方法调用,这是行不通的,事实上目前没有办法做到这一点。
( 注意:我只是扩大了Firas Assad提供的答案 。)
我们可以通过仅实例化我们实际需要的帧而不是整个堆栈来改进阿萨德先生的代码(目前被接受的答案)
new StackFrame(1).GetMethod().Name;
这可能会更好一些,虽然很可能它仍然需要使用完整的堆栈来创build单个帧。 而且,Alex Lyman也指出了相同的注意事项(优化器/本地代码可能会破坏结果)。 最后,您可能需要检查以确保new StackFrame(1)
或.GetFrame(1)
不会返回null
,尽可能不可能如此。
看到这个相关的问题: 你可以使用reflection来find当前正在执行的方法的名称?
速度比较的两种方法的快速回顾是重要的一部分。
在编译时确定调用者
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); }
使用堆栈确定调用者
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); }
两种方法的比较
Time for 1,000,000 iterations with Attributes: 196 ms Time for 1,000,000 iterations with StackTrace: 5096 ms
所以你看,使用属性要快得多! 事实上快了25倍。
请注意,由于优化,在发布代码中这样做将不可靠。 另外,在沙盒模式下运行应用程序(networking共享)将不会让您抓取堆栈框架。
考虑面向方面的编程 (AOP),就像PostSharp一样,它不是从你的代码中调用,而是修改你的代码,从而知道它在哪里。
/// <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; }
也许你正在寻找这样的东西:
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
显然这是一个迟到的答案,但是如果你可以使用.NET 4.5或更高版本,我有更好的select:
internal static void WriteInformation<T>(string text, [CallerMemberName]string method = "") { Console.WriteLine(DateTime.Now.ToString() + " => " + typeof(T).FullName + "." + method + ": " + text); }
这将打印当前date和时间,然后是“Namespace.ClassName.MethodName”,并以“:text”结尾。
示例输出:
6/17/2016 12:41:49 PM => WpfApplication.MainWindow..ctor: MainWindow initialized
样品使用:
Logger.WriteInformation<MainWindow>("MainWindow initialized");
您现在可以使用来电者信息属性:
- CallerFilePath – 调用函数的cs文件;
- CallerLineNumber调用函数的代码行;
-
CallerMemberName – 调用函数的成员。
public void WriteLine( [CallerFilePath] string callerFilePath= "", [CallerLineNumber] long callerLineNumber= 0, [CallerMemberName] string callerMember= "") { Debug.WriteLine(string.Format("Caller File Path: {0}, Caller Line Number: {1}, Caller Member: {2}", callerFilePath, callerLineNumber, callerMember)); }
private static MethodBase GetCallingMethod() { return new StackFrame(2, false).GetMethod(); } private static Type GetCallingType() { return new StackFrame(2, false).GetMethod().DeclaringType; }
一个梦幻般的课程在这里: http : //www.csharp411.com/c-get-calling-method/
我使用的另一种方法是向所讨论的方法添加一个参数。 例如,而不是void Foo()
,使用void Foo(string context)
。 然后传入一些指示调用上下文的唯一string。
如果您只需要调用者/上下文进行开发,您可以在发货前删除param
。
在.NET中查看日志logging方法名称 。 谨防在生产代码中使用它。 StackFrame可能不可靠…
我们也可以使用lambda来查找调用者。
假设你有一个由你定义的方法:
public void MethodA() { /* * Method code here */ }
你想find它的来电。
1 。 改变方法签名,所以我们有一个Actiontypes的参数(Func也可以):
public void MethodA(Action helperAction) { /* * Method code here */ }
2 。 Lambda名称不是随机生成的。 规则似乎是:> <CallerMethodName> __ X其中CallerMethodName被前一个函数replace,X是一个索引。
private MethodInfo GetCallingMethodInfo(string funcName) { return GetType().GetMethod( funcName.Substring(1, funcName.IndexOf(">", 1, StringComparison.Ordinal) - 1) ); }
3 。 当我们调用MethodA时,Action / Func参数必须由调用方法生成。 例:
MethodA(() => {});
4 。 在MethodA中,我们现在可以调用上面定义的帮助函数,并find调用方法的MethodInfo。
例:
MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name);
StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1); string methodName = caller.GetMethod().Name;
我想,就足够了。
var callingMethod = new StackFrame(1, true).GetMethod(); string source = callingMethod.ReflectedType.FullName + ": " + callingMethod.Name;