咨询区
-
flipdoubt:
当我用 C# 记录日志的时候,我如何知道当前方法的调用者是谁?我知道有一个 System.Reflection.MethodBase.GetCurrentMethod()
方法,但我想获取更深一步的 堆栈信息
,我考虑过解析调用堆栈,但我希望能找到一个更加干净简洁的方式,类似于用 Assembly.GetCallingAssembly()
捕获方法调用者的程序集。.
回答区
-
Coincoin:
如果你使用 C#5 + 的话,推荐使用 caller info
, 如下代码所示:
class Program
{
static void Main(string[] args)
{
SendError("hello world!");
}
public static void SendError(string Message, [CallerMemberName] string callerName = "")
{
Console.WriteLine(callerName + " called me.");
}
}

除了调用者,还可以获取调用者的路径 [CallerFilePath]
和 行号 [CallerLineNumber]
。
Tikall
有两种方式可以实现。
-
特性 -
Stack
下面我比较一下它们的性能差异。
-
编译时判断调用者
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);
}
-
Stack 中判断调用者
static void Log2(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
正如你看到的,使用 特性
是相当快的,实际上比 Stack 快将近 25 倍。
点评区
获取当前执行方法的调用者,其实我只知道 Stack
这种方式,有意思的是 Tikall
大佬提到的:特性比 Stack 快 25 倍,乍一看挺夸张的,那我就来简单验证下。
-
测试环境:.NET5 & x64 & Windows10 & Release
public class Program
{
static void Main(string[] args)
{
var mystest = new MyTest();
var watch = Stopwatch.StartNew();
for (int i = 0; i < 10000; i++)
{
mystest.Log($"hello");
}
watch.Stop();
var watch2 = Stopwatch.StartNew();
for (int i = 0; i < 10000; i++)
{
mystest.Log2($"world");
}
watch2.Stop();
Console.WriteLine($"Log={watch.ElapsedMilliseconds}s, Log2={watch2.ElapsedMilliseconds}s");
}
}
public class MyTest
{
public 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);
}
public void Log2(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);
}
}

从图中可以看出,大概有 5 倍的差距,这也许是 .NET 5
中对 Stack 做了优化吧~~~
原文链接:https://stackoverflow.com/questions/171970/how-can-i-find-the-method-that-called-the-current-method