是否建议使用MethodBase来查找用于日志记录的方法名?

本文关键字:记录 日志 方法 用于 查找 MethodBase 是否 | 更新日期: 2023-09-27 17:50:31

我的源代码中几乎每个函数都有以下代码:

string methodName = MethodBase.GetCurrentMethod().Name;

我的问题是

是否建议使用上面的代码来实现相同的考虑反射是一个昂贵的事情?

是否建议使用MethodBase来查找用于日志记录的方法名?

不,我不会在源代码的所有地方都这样做。

首先,我会使用专用的日志包,它可能有更好的方法来完成工作,并且在源代码中肯定不会那么突兀。有各种可用的选项(log4net, nlog等)。方法名到底有多重要?我通常发现,如果我在消息中使用足够的上下文进行日志记录,我不需要知道确切的方法名称。

其次,如果你使用c# 5,你可以使用CallerMemberNameAttribute让编译器为你指定调用日志函数的方法的名称。这显然比在执行时执行要明智得多。

使用这种方法获取当前方法的名称会对性能造成很大的影响,所以我不推荐使用这种方法。

人们经常提到CallerMemberNameAttribute类,但是现在您想要使用日志记录接口时,这通常不太适合。这样做的原因是它通常作为默认参数应用,这意味着它必须在非默认参数的右边。许多日志API的格式为:

Info(string format, params object[] values)

现在,添加一个具有CallerMemberNameAttribute的参数将是一个问题。你不能把它放在右边,因为params参数禁止这样做,你也不能把它放在其他任何地方,因为它不符合作为默认参数的条件。一种选择是将日志API更改为如下内容:

Info(string format, object[] values, [CallerMemberName] string memberName = "")

但是你必须显式地为这些值创建一个数组,这往往不是流。

出于好奇,我决定计时GetCurrentMethod调用。使用Stopwatch,我在循环中调用GetCurrentMethod,看起来没有缓存(呼叫号码和时间之间的线性关系)

var sw = new System.Diagnostics.Stopwatch();
sw.Start();
for (var i = 0; i < numberOfCallsToMake; i++)
{
    var methodName = MethodBase.GetCurrentMethod().Name;
}
sw.Stop();
Console.WriteLine("Calling GetCurrentMethod {0} times: {1} ms",numberOfCallsToMake,  sw.ElapsedMilliseconds);

得到

Calling GetCurrentMethod 100 times: 0 ms
Calling GetCurrentMethod 1000 times: 1 ms
Calling GetCurrentMethod 10000 times: 14 ms
Calling GetCurrentMethod 100000 times: 148 ms
Calling GetCurrentMethod 1000000 times: 1335 ms
Calling GetCurrentMethod 10000000 times: 13403 ms
Calling GetCurrentMethod 100000000 times: 134079 ms

看起来没有任何方法名的缓存(不知道这是如何工作的),因为时间和调用次数之间存在线性关系。

一个日志框架可能会更聪明,存储当前的方法名,以减少这些毫秒,你也会从中获得额外的好处。所以遵循Jon Skeet的建议,使用日志框架