【问题标题】:Multiple methods that need to be handled the same way需要以相同方式处理的多种方法
【发布时间】:2008-11-10 13:43:30
【问题描述】:

在我正在编写的一段 C# 中,我需要以相同的方式处理具有相同签名的多个方法。将来可能还会有更多这些方法。我没有一遍又一遍地重复相同的逻辑,而是想到了以下内容:

private delegate bool cleanStep(BuildData bd, out String strFailure);

List<cleanStep> steps = new List<cleanStep>();
steps.Add(WriteReadme);
steps.Add(DeleteFiles);
steps.Add(TFSHelper.DeleteLabel);
steps.Add(TFSHelper.DeleteBuild);

List<cleanStep>.Enumerator enumerator = steps.GetEnumerator();
bool result = true;
while (result && enumerator.MoveNext())
{
   result = enumerator.Current.Invoke(build, out strFailure);
   if (!result)
   {
      logger.Write(LogTypes.Error, strFailure);
   }
}

我认为这有一些不错的功能,但也感觉有点过度设计和混淆。

你能感谢一个更好的方法吗?

顺便说一句:

  • 它不需要是事务性的。
  • strFailure 不会隐藏异常,而是将它们包装起来 必要时完全完成

谢谢。

【问题讨论】:

    标签: c# delegates


    【解决方案1】:

    为什么不使用 foreach 循环并直接中断? (我在这里将 cleanStep 重命名为 CleanStep 以保持常规 - 我建议你也这样做。)

    foreach(CleanStep step in steps)
    {
        string failureText;
        if (!step(build, out failureText))
        {
            logger.Write(LogTypes.Error, strFailure);
            break;
        }
    }
    

    请注意,这也遵守 IEnumerator&lt;T&gt; 的约定,而您当前的代码不这样做 - foreach 自动调用 Dispose,而 IEnumerator&lt;T&gt; 实现 IDisposable。在这种情况下,这不是问题,但对于迭代器块,disposal is used to execute finally blocks

    【讨论】:

    • 看起来已经更好了。还学到了有关处理枚举数的新知识。谢谢。我对 break 语句有点反感,但在这里它确实是有道理的。
    【解决方案2】:

    您的解决方案既简单明了又易于理解。我看不出有什么理由换一种方式:)

    我建议的唯一方法是用 foreach 循环替换您的迭代器并在错误时中断。

    【讨论】:

      【解决方案3】:

      重新混淆 - 好吧 foreach 加上 break 可能会更清楚(加上它会 Dispose() 枚举器,你没有这样做)。

      实际上,“params cleanStep[] 目标”可能会有所帮助:

      static bool RunTargets(params cleanStep[] targets)
      {
          // detail as per Jon's post
      }
      

      然后你可以调用:

      bool foo = RunTargets(WriteReadme, DeleteFiles,
                    TFSHelper.DeleteLabel, TFSHelper.DeleteBuild);
      

      【讨论】:

      • 谢谢,这实际上是我喜欢的功能之一。你可以把这个函数重构出来,也可以创建列表。
      【解决方案4】:

      我会返回一个异常对象而不是一个字符串。由于异常通常具有全局策略,因此我会编写一些异常扩展。现在你得到:

      static Exception Run( this IEnumerable<Step> steps) {
         return 
             steps
             .FirstOrDefault( (step) => step( build ) != null )
             .LogIfFailure();  //or .ThrowIfFailure()
      }
      

      扩展:

      public static class ExceptionExtensions {
          private static logger = new Logger();
      
          public static Exception LogIfFailure( this Exception e ) {
              if( e != null )
                  logger.Write( e.Message );
              return e;
          }
          public static Exception ShowDialogIfFailure( this Exception e ) {
              if( e != null )
                  MessageBox.Show( e.Message );
              return e;
          }
          public static void ThrowIfFailure( this Exception e ) {
              if( e != null )
                  Throw( e );
          }
      }
      

      【讨论】:

      • 谢谢。我喜欢干净的 foreach,但是当一个步骤失败时它不会停止。我知道我说过它不需要是事务性的,但是当一个步骤失败时,我们甚至不希望它尝试其余的步骤。
      猜你喜欢
      • 1970-01-01
      • 2019-12-15
      • 2019-09-06
      • 1970-01-01
      • 1970-01-01
      • 2018-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多