8

我有许多方法需要一些具有相同模式的日志记录。有些方法需要返回一些值,有些则不需要。我创建了一个带有 Action 参数的方法,以避免复制粘贴所有逻辑。它看起来像这样:

private void Execute(Action action)
{
   Logger.Start();
   try
   {
      action();
   }
   catch(Exception exception)
   {
      Logger.WriteException();
      throw;
   }
   finally
   {
       Logger.Finish();
   }
}

现在我有一些这样的电话

public void DoSomething(string parameter)
{
    Execute(() => GetProvider(parameter).DoSomething());
}

但我需要一些返回值的函数。最好的方法是什么?我现在找到了两个:

1) 使用 Func 创建 Execute 方法的副本

private T Execute<T>(Func<T> action)
{
   Logger.Start();
   try
   {
      return action();
   }
   catch(Exception exception)
   {
      Logger.WriteException();
      throw;
   }
   finally
   {
       Logger.Finish();
   }
}

此方法有效,但也有一些复制粘贴。

2)欺骗参数成为一个动作:

public Result DoSomething(string parameter)
{
    Result result = null;
    Execute(() => result = GetProvider(parameter).DoSomething());
    return result;
}

这不需要复制粘贴,但看起来不太好。

有没有办法以某种方式加入 Action 和 Func 以避免这些方法中的任何一种,或者可能有另一种方法来实现相同的结果?

4

3 回答 3

7

第三种选择仍然是重载Execute,但使Action版本根据版本工作Func

private void Execute(Action action)
{
    // We just ignore the return value here
    Execute(() => { 
        action();
        return 0; 
    });
}

当然,如果void更像是“真实”类型(如UnitF# 等),这一切都会更简单,此时我们可以只拥有Task<T>而不是Taskand Task<T>......

于 2013-04-02T13:36:44.930 回答
3

创建一个将Execute转换FuncAction. 您只需要编写一次丑陋的代码,并且您不会得到该Execute方法的完整的第二个副本:

private T Execute<T>(Func<T> func)
{
    T result = default(T);
    this.Execute(() => { result = func(); });
    return result;
}

...

public Result DoSomething(string parameter)
{
    return Execute(() => GetProvider(parameter).DoSomething());
}
于 2013-04-02T13:40:21.517 回答
2

这是另一种选择。不要让日志框架调用您的实际代码,而是让您的实际代码调用日志框架。像这样的东西可以解决问题(大大简化)。

public class LoggerScope : IDisposable {

    private bool disposed;

    public LoggerScope() {
        Logger.Start();
    }

    public void Dispose() {
        if(!disposed) {
            Logger.Finish();
            disposed = true;
        }
    }
}

使用如下:

        using(var scope = new LoggerScope()) {
            // actual code goes here
        }

通过在代码的顶层仅捕获和记录一次异常来单独处理异常。

好处:

  • 避免到处都需要 lambda,因此异常堆栈跟踪更加清晰。
  • 您可以向LoggerScope类添加任意上下文数据,例如 GUID、时间戳、逻辑任务描述文本。
于 2013-04-02T14:35:36.093 回答