【问题标题】:Refactor class to avoid writing same pattern in every method重构类以避免在每个方法中编写相同的模式
【发布时间】:2014-08-06 09:37:17
【问题描述】:

我有一个类,其中包含许多用于管理数据库操作的静态方法。所有方法都遵循这种模式:

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);
}    

【问题讨论】:

  • 仅供参考 - ex.ToString() 比 ex.Message 更有用很多。
  • 您正在寻找模板方法模式

标签: c# entity-framework design-patterns try-catch using


【解决方案1】:

听起来您应该将“方法体”作为委托传递:

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
});

如 cmets 中所述,您可能希望重载:

public void GiveMeAProperName<T>(Func<DBContext, T> databaseAction)

这样你就可以返回一个值。您可以轻松地编写您的 Action 重载来委派给它:

public void GiveMeAProperName(Action<DBContext> databaseAction)
{
    GiveMeAProperName(context =>
    {
        databaseAction(context);
        return "ignored";
    }
}

我强烈建议不同的异常处理方式:

  • 您只是在记录消息。为什么你认为堆栈跟踪不重要?只需记录整个异常 - 这将包括嵌套异常等
  • 之后你实际上忽略了失败。在大多数情况下,我个人会完全摒弃 try/catch……在非常高的级别上捕获异常,而不是在执行数据库操作的级别上。

【讨论】:

  • 使用Func&lt;Context, T&gt; 会更好吗?某些操作可能需要返回数据?
  • @RobH:可能 - 会添加。
  • @JonSkeet 谢谢,您是否介意修改我已尝试实施您的回复的已编辑问题。特别是 IDE 不允许我按照您的建议通过无参数调用委托来编写 Action 重载。
  • @JPG:“没有让我”没有让我知道出了什么问题……总是给出完整的错误信息。 (此外,将解决方案添加到问题中并没有多大意义。)
  • @JonSkeet 错误出现在 databaseAction() 中:“Delegate 'Action' 不接受 0 个参数”。关于用解决方案编辑我的问题,我这样做是因为我不确定我的理解是否完全正确。
【解决方案2】:

创建静态方法:

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
});

【讨论】:

    【解决方案3】:

    您可以创建一个具有该包装器的通用方法并调用您提供的委托:

    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,重新抛出异常会为调用方法提供更多关于出错原因的信息。

    【讨论】:

      猜你喜欢
      • 2021-07-03
      • 2018-03-14
      • 1970-01-01
      • 2012-06-28
      • 1970-01-01
      • 1970-01-01
      • 2015-12-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多