我有一个场景,我想抓住该集合被修改的异常并重试。
一种方法是使用when和匹配本地化的Message。这假设有一种方法来挖掘信息。
我想避免更改CurrentUICulture
,因为它可能会产生副作用。
希望有一种我能想到的更好的方式。
伪代码:
public void Refresh()
{
try
{
...
}
catch (InvalidOperationException e) when (e.Message == Environment.GetCollectionWasModifiedMessage())
{
Refresh(); // retry
}
}
答案 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
的情况,您如何安全地并正确地处理此特定异常?
嗯,你没有。
有两个原因可能会在循环中获得此特定异常和消息:
在两者这些情况下,错误的做法是捕获异常。
应该以有效执行以下操作之一的方式处理第一个场景:
您可以在循环之前创建集合的快照,然后枚举快照,然后在.ToList()
内的foreach
上完成此操作:
foreach (var element in collection.ToList())
您可以创建要修改集合的操作列表,并仅在完全枚举原始集合后应用这些操作
类似的东西:
var toDelete = new List<T>();
foreach (var element in collection)
if (ShouldDelete(element))
toDelete.Add(collection);
foreach (var element in toDelete)
collection.Remove(element);
另一种情况,你真的不想要这种情况。解决此问题的唯一方法是确保使用线程安全集合,而不是修改多个线程共享的数据。即使您在执行此操作时没有遇到异常,这也是灾难的秘诀。