在一个参数中组合Action和function
本文关键字:组合 Action function 参数 一个 | 更新日期: 2023-09-27 18:06:57
我有许多方法需要相同模式的日志记录。有些方法需要返回值,有些不需要。我创建了一个带有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)欺骗参数为Action:public Result DoSomething(string parameter)
{
Result result = null;
Execute(() => result = GetProvider(parameter).DoSomething());
return result;
}
不需要复制粘贴,但看起来不太好。
是否有一种方法可以连接Action和Func以避免任何这些方法,或者可能有另一种方法来实现相同的结果?
第三种选择是仍然重载Execute
,但使Action
版本根据Func
版本工作:
private void Execute(Action action)
{
// We just ignore the return value here
Execute(() => {
action();
return 0;
});
}
当然,如果void
更像一个"真正的"类型(如f#等中的Unit
),那么这一切都会更简单,在这一点上,我们可以只使用Task<T>
而不是Task
和Task<T>
…
创建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());
}
这是另一个选项。与其让日志框架调用实际代码,不如让实际代码调用日志框架。类似这样的操作就可以达到目的(大大简化)。
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,时间戳,逻辑任务描述文本。