我有很多方法需要使用相同的模式进行一些日志记录。有些方法需要返回一些值,有些则不需要。我已经创建了一个带有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以避免任何这些方法,或者可能有另一种方法来实现相同的结果?
答案 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>
Task
和Task<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
}
通过在代码的顶层捕获并记录一次异常来单独处理异常。
优点:
LoggerScope
类,例如GUID,时间戳,逻辑任务描述文本。