在一个参数中组合Action和Func

时间:2013-04-02 13:34:12

标签: c# .net delegates action func

我有很多方法需要使用相同的模式进行一些日志记录。有些方法需要返回一些值,有些则不需要。我已经创建了一个带有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以避免任何这些方法,或者可能有另一种方法来实现相同的结果?

3 个答案:

答案 0 :(得分:6)

第三个选项仍然是重载Execute,但Action版本的工作方式是Func

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

当然,如果void更像“真实”类型(如F#等人中的Unit),那么所有这些都会更简单,此时我们可以改为Task<T> TaskTask<T>也是......

答案 1 :(得分:3)

创建Execute的副本,将Func转换为Action。您只需编写一次难看的代码,并且最终不会得到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());
}

答案 2 :(得分: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
        }

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

优点:

  • 避免在整个地方需要lambdas,因此异常堆栈跟踪更清晰。
  • 您可以将任意上下文数据添加到LoggerScope类,例如GUID,时间戳,逻辑任务描述文本。