【问题标题】:Continue try block after catch. Log all exceptions in one try catchcatch 后继续 try 块。在一次尝试中记录所有异常
【发布时间】:2020-12-24 22:03:45
【问题描述】:

我想做 4 个动作,每个动作都可以抛出一个异常。我需要全部执行并记录沿途发生的所有错误

我可以大而笨拙地做到这一点:

var exceptions = new List<ExceptionType1>();
try {
    result1 = await action1();
} catch (ExceptionType1 ex1) {
    exceptions.Add(ex1);
    logger.Log(ex1);
}

try {
    result2 = await action2();
} catch (ExceptionType1 ex1) {
    exceptions.Add(ex1);
    logger.Log(ex1);
}

try {
    result3 = await action3(result1);
} catch (ExceptionType2 ex2) {
    var ex1 = new ExceptionType1(ex2);
    exceptions.Add(ex1);
    logger.Log(ex1);
}

try {
    result4 = await action4(result2);
} catch (ExceptionType2 ex2) {    
    var ex1 = new ExceptionType1(ex2);
    exceptions.Add(ex1);    
    logger.Log(ex1);
}

if (exceptions.Count > 0) {
    return false;
}

显然,有时像这样的东西会迅速膨胀 我想以更优雅的方式做到这一点:

var exceptions = new List<ExceptionType1>();
try {
    result1 = await action1();
    result2 = await action2();
    result3 = await action3(result1);
    result4 = await action4(result2);
} catch(Exception ex) {
    var ex1 = new ExceptionType1(ex);
    exceptions.Add(ex1);
    logger.Log(ex1);
    ???
    ~~Goto try block and continue executing~~
    ???

}

if (exceptions.Count > 0) {
    return false;
}    

我试图找到有关如何返回 try 块并继续执行的信息,但未成功。可能吗。有没有其他我没有考虑过的解决方法?

【问题讨论】:

  • 为什么你首先会有像result1result2result3这样的变量。它们似乎可以放入数组/列表中,然后您可以使用循环。
  • @Sweeper 我从各种来源获取数据并希望将它们组合到一个对象中。我看不出如何在这里使用循环。
  • 那么不同的结果都是不同的类型?
  • 那种。实际上,我将 action1 的结果用于 action3。以及 action2 的 action4 的结果。动作 1,2 和 3,4 是同一类型。我认为这些细节对于这个主题来说是不必要的。
  • 不确定这个问题是否对您有帮助:stackoverflow.com/questions/4217643/task-waitall-and-exceptions

标签: c# exception logging try-catch


【解决方案1】:

我猜的一种方法(考虑到你的重新装备)是创建一个本地方法

var exceptions = new List<Exception>();

async Task<T> DoAsync<T>(Func<Task<T>> func)
{
   try
   {
      return await func();
   }
   catch (Exception ex)
   {
      exceptions.Add(ex);
      logger.Log(ex);
   }

   return default;
}

result1 = await DoAsync(action1);
result2 = await DoAsync(action2);

if (exceptions.Count > 0)
{
   return false;
}

【讨论】:

    【解决方案2】:

    也许您可以将其提取到local function

    // declare this inside the method that contains the code you showed
    async void GetResult<TResult, TException>(out TResult result, Func<Task<TResul>> resultGetter, Func<TException, ExceptionType1> mapper)
        where TException: Exception {
        try {
            result = await resultGetter();
        } catch (TException ex) {
            var ex1 = mapper(ex)
            exceptions.Add(ex1);
            logger.Log(ex1);
        }
    }
    

    来电者:

    GetResult(out result1, action1, (ExceptionType1 e) => e);
    GetResult(out result2, action2, (ExceptionType1 e) => e);
    GetResult(out result3, async () => await action3(result1), (ExceptionType2 e) => new ExceptionType1(e));
    GetResult(out result4, async () => await action4(result2), (ExceptionType2 e) => new ExceptionType1(e));
    

    【讨论】:

      【解决方案3】:

      如何回到 try 块并继续执行.. 有可能吗?

      你不能做你正在寻找的东西:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch

      块一直执行,直到抛出异常或成功完成。

      一旦出块,连已经初始化的变量也会回滚。

      停止执行受安全保护的代码是异常的全部意义。

      按照其他两个答案的建议来简化您的代码

      【讨论】:

      • 他确实问过这是否可能。我不想用其他答案中已有的信息来夸大答案。
      【解决方案4】:

      我认为 Task 的 WhenAll() 方法将适合您的目的: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch#taskwhenall-example 首先,您的操作已经是异步的。此外,如果您需要遵循任何执行顺序,您可以划分为多个 WhenAll() 块

      来自文档的示例:

      public async Task action1()
      {
          throw new InvalidOperationException();
      }
      public async Task action2()
      {
          throw new NotImplementedException();
      }
      
      public async Task action3()
      {
          throw new InvalidCastException();
      }
      public async Task DoMultipleAsync()
      {
          Task theTask1 = action1();
          Task theTask2 = action2();
          Task theTask3 = action3();
      
          Task allTasks = Task.WhenAll(theTask1, theTask2, theTask3);
      
          try
          {
              await allTasks;
          }
          catch (Exception ex)
          {
              Console.WriteLine("Exception: " + ex.Message);
              Console.WriteLine("Task IsFaulted: " + allTasks.IsFaulted);
              foreach (var inEx in allTasks.Exception.InnerExceptions)
              {
                  Console.WriteLine("Task Inner Exception: " + inEx.Message);
              }
          }
      }
      
      // Output:
      // Exception: Operation is not valid due to the current state of the object.
      // Task IsFaulted: True
      // Task Inner Exception: Operation is not valid due to the current state of the object.
      // Task Inner Exception: The method or operation is not implemented.
      // Task Inner Exception: Specified cast is not valid.
      
      

      【讨论】:

      • 您能就我的情况提供解决方案吗?这看起来像我想使用的东西。如果某些操作不是异步的,这会起作用吗?
      • 用你的例子更新了
      猜你喜欢
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-09
      • 2014-08-23
      • 2018-02-20
      相关资源
      最近更新 更多