重构类以避免在每个方法中编写相同的模式
本文关键字:模式 方法 重构 | 更新日期: 2023-09-27 18:16:41
我有一个类,其中有许多用于管理数据库操作的静态方法。所有方法都遵循以下模式:
try
{
using(var trans = new TransactionScope())
{
using(var context = new DBContext())
{
. . . // method body
}
trans.Complete();
}
}
catch(Excepcion ex)
{
Log.Error(ex.Message);
if (ex.InnerException != null)
Log.Error(ex.InnerException.Message);
}
我如何重构我的代码,使它不需要在每个方法中都写这个结构?
编辑实现Jon的回应。
public static T TransactionalOperation<T>(Func<DBContext, T> databaseAction)
{
T retVal = default(T);
try
{
using (var trans = new TransactionScope())
{
using (var context = new DBContext())
{
if (databaseAction != null)
retVal = databaseAction(context);
}
trans.Complete();
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
return retVal;
}
public static void TransactionalOperation(Action<DBContext> databaseAction)
{
TransactionalOperation(context =>
{
databaseAction(context);
return string.Empty;
});
}
像这样使用:
public static string GetUserLanguage(string owner)
{
return
TransactionalOperator(context => context.clients.Single(c => c.Id == owner).Language);
}
听起来你应该把"method body"作为委托传入:
public void GiveMeAProperName(Action<DBContext> databaseAction)
{
try
{
using(var trans = new TransactionScope())
{
using(var context = new DBContext())
{
. . . // method body
}
trans.Complete();
}
}
catch(Exception ex)
{
Log.Error(ex.Message);
if (ex.InnerException != null)
Log.Error(ex.InnerException.Message);
}
}
然后你可以用:
GiveMeAProperName(context =>
{
// Do stuff with your context here
});
如注释中所述,您可能希望重载:
public void GiveMeAProperName<T>(Func<DBContext, T> databaseAction)
以便返回一个值。您可以轻松地编写Action
过载,将其委托给它:
public void GiveMeAProperName(Action<DBContext> databaseAction)
{
GiveMeAProperName(context =>
{
databaseAction(context);
return "ignored";
}
}
我强烈建议使用不同的异常处理方法:
- 您只记录消息。为什么你认为堆栈跟踪不重要?只需记录整个异常—包括嵌套异常等 你实际上忽略了之后的失败。在大多数情况下,我个人会完全取消尝试/捕获……在非常高的级别捕获异常,而不是在执行数据库操作的级别。
创建静态方法:
public static void UsingDBContext(Action<DBContext> action){
try
{
using(var trans = new TransactionScope())
{
using(var context = new DBContext())
{
action(context);
}
trans.Complete();
}
}
catch(Exception ex)
{
Log.Error(ex.Message);
if (ex.InnerException != null)
Log.Error(ex.InnerException.Message);
}
}
然后:
UsingDbContext( con => {
..'' write your code here
});
您可以创建一个泛型方法,该方法具有该包装器并调用您提供的委托:
private static T Call<T>(Func<DbContext, T> func) {
T result = null;
try {
using(var trans = new TransactionScope()) {
using(var context = new DBContext()) {
result = func(context);
}
trans.Complete();
}
} catch(Excepcion ex) {
Log.Error(ex.Message);
if (ex.InnerException != null) {
Log.Error(ex.InnerException.Message);
}
}
return result;
}
使用例子:
List<int> someValues = Call(context => {
// some code that uses context and returns a list of ints
});
由于返回类型是泛型的,您可以让它返回任何您想要的类型。它甚至可以是匿名类型。
但是,您应该考虑在方法中重新抛出异常。现在,当出现错误时,它只会返回null
,重新抛出异常会给调用方法更多的信息,让它知道是什么出错了。