3

不记得更好的标题,请随意将其更改为更好的名称:)

我的应用程序包含很多日志记录语句,如下所示:

var logger = new Logger(/*..get flag from settings if the logger should be active..*/);
// ....
logger.LogActivity(..serialize an object..);
//...
logger.LogActivity(..get another object's expensive overriden ToString method..);
//...
logger.LogActivity(..log something new..);

记录器类:

public class Logger
{
  private readonly bool _isActive;

  public Logger(bool isActive)
  {
    _isActive = isActive;
  }

  public void LogActivity(string activity)
  {
    if (_isActive)
    {
      // Save activity to Database.
    }
  }
}

当我在设置中禁用记录器时(因此 Logger 类中的 _isActive 字段为假),则没有任何内容保存到数据库中。但是 Logger.LogActivity 方法中的所有表达式仍然被评估(例如 ..serialize object.. 在前面的例子中),这会减慢我的应用程序。我可以使用这样的日志语句:

var logger = new Logger(/*..get flag from settings if the logger should be active..*/);
// ....
if (loggerIsActive) logger.LogActivity(..serialize an object..);
//...
if (loggerIsActive) logger.LogActivity(..get another object's expensive overriden ToString method..);
//...
if (loggerIsActive) logger.LogActivity(..log something new..);

但是只更改 LogActivity 方法会更好......是否可以以某种方式仅更改 LogActivity 方法,以便在禁用记录器时,不评估 LogActivity 调用中的表达式?好吧 - 如果这在 C# 中是可能的,我会感到惊讶,但是有没有其他方法/模式可以做到这一点?

4

2 回答 2

4

您可以添加一个重载,该重载Func<string>将生成要记录的字符串。

public void LogActivity(Func<string> activity)
{
    if (_isActive)
    {
        string log = activity();
        // save 'log' to database
    }
}

然后像这样使用它:

logger.LogActivity(() => expensiveObject.ToString());
于 2012-06-20T10:57:04.493 回答
1

您不能完全避免参数评估,不,但您可以提供一些额外的日志记录方法来帮助您。

@Martin 和 @kenny 建议传递 lambda 表达式。这将推迟代码的评估,但会导致丑陋的客户端代码。您可能会节省几个周期,但我怀疑这是否值得。

我建议您创建几个 LogActivity 覆盖:

LogActivity(string message) // logs the message
LogActivity(object obj) // calls obj.ToString() and logs it

如果您认为确实有必要,请保留 lambda 表达式变体:

LogActivity(Func<String> func) // evaluates the function and logs its response

请注意,您将无法避免调用 LogActivity 的成本。C# 不是 C,而且您没有像在 C 中那样工作的宏。这几乎不是问题,如果调用非虚拟方法对您来说代价高昂,那么您经常这样做,您不应该这样做无论如何,将日志消息放在那里。

于 2012-06-20T11:24:14.440 回答