Catch集合被修改了异常

时间:2015-09-23 17:45:42

标签: c# .net exception c#-6.0

我有一个场景,我想抓住该集合被修改的异常并重试。

一种方法是使用when和匹配本地化的Message。这假设有一种方法来挖掘信息。

我想避免更改CurrentUICulture,因为它可能会产生副作用。

希望有一种我能想到的更好的方式。

伪代码:

public void Refresh()
{
    try
    {
        ...
    }
    catch (InvalidOperationException e) when (e.Message == Environment.GetCollectionWasModifiedMessage())
    {
        Refresh(); // retry
    }
}

1 个答案:

答案 0 :(得分:2)

首先,处理特定异常的方法是您已经发现的中途:

try
{
    ...
}
catch (SpecificException ex)
{
    ...
}

然而,当你必须检查信息时,你会陷入困境。无法保证此消息使用您编写程序的语言。也许可能是针对此特定错误消息,但它可能包含已翻译的错误消息。如果有问题的异常类型有其他方法来确定导致异常的特定原因,那么这些通常要好得多。寻找像HResult,ErrorCode等的东西。

您可以像这样编写此代码:

try
{
    ...
}
catch (SpecificException ex)
{
    if (ex.ErrorCode == 1)
        ...
}

在C#6中你甚至可以写得更好一点:

try
{
    ...
}
catch (SpecificException ex) when (ex.ErrorCode == 1)
{
}

因此,对于这种引发InvalidOperationException的情况,您如何安全地正确地处理此特定异常?

嗯,你没有。

有两个原因可能会在循环中获得此特定异常和消息:

  1. 你正在修改你自己列举的集合,即。作为循环的一部分,您修改源集合
  2. 其他(不同的主题)在您对其进行枚举时正在修改该集合
  3. 两者这些情况下,错误的做法是捕获异常。

    应该以有效执行以下操作之一的方式处理第一个场景:

    1. 您可以在循环之前创建集合的快照,然后枚举快照,然后在.ToList()内的foreach上完成此操作:

      foreach (var element in collection.ToList())
      
    2. 您可以创建要修改集合的操作列表,并仅在完全枚举原始集合后应用这些操作

      类似的东西:

      var toDelete = new List<T>();
      foreach (var element in collection)
          if (ShouldDelete(element))
              toDelete.Add(collection);
      
      foreach (var element in toDelete)
          collection.Remove(element);
      
    3. 另一种情况,你真的不想要这种情况。解决此问题的唯一方法是确保使用线程安全集合,而不是修改多个线程共享的数据。即使您在执行此操作时没有遇到异常,这也是灾难的秘诀。