2015-09-23 77 views
0

我有一個場景,我想捕捉集合被修改的異常並重試。捕捉集合被修改異常

一種方法是使用何時與匹配本地化的消息。這假設有一種方法來挖掘該消息。

我想避免更改CurrentUICulture,因爲它可能有副作用。

希望有一個更好的方式,我想不出來。

僞代碼:

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

一種方法是強制拋出異常並保存消息:) –

+0

是的,優雅:) –

+2

當我看到一個異常e.Message的檢查,我假設所有「優雅」是已經丟失:D –

回答

2

首先,處理特定異常的方式是中途你已經發現了什麼:

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

但是,當你要檢查你正在困擾水中的信息。不能保證這個消息是用你編寫程序的語言寫的。也許這可能是針對這個特定的錯誤信息,但它可能包含一個翻譯的錯誤信息。如果所討論的異常類型有其他方法來確定哪個特定原因導致異常,那麼這些通常會好很多。認準的事像HResult的,錯誤碼等

你會寫這樣的代碼是這樣的:

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

在C#6你甚至可以寫這個略勝一籌:

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

所以,這種情況下,拋出一個InvalidOperationException,你怎麼安全正確處理這個特殊的例外?

那麼,你沒有。


有兩個原因你可能在一個循環中得到這個特定的異常和消息:

  1. 你修改集合你列舉了自己,即。作爲循環的一部分修改源收集
  2. 別的東西(不同的線程)的修改集合,而你列舉了它

兩種這些情況下,錯誤的做法是抓例外。

第一種方案應該以這樣的方式,你有效地執行下列操作之一來處理:

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

其他情況下,你真的不希望這種情況下。解決此問題的唯一方法是確保您使用線程安全集合,並且不要修改多線程共享的數據。即使您在碰巧沒有發生異常時,這也是一種災難性的處方

+0

有upvote我的朋友。我仍然很好奇當'when':) :) –

+0

'InvalidOperationException'有一個HResult屬性,但它似乎沒有包含已知的值。 –

+0

不,它包含[this:0x80131509](https://msdn.microsoft.com/en-us/library/windows/desktop/ee671218%28v=vs.85%29.aspx):UIA_E_INVALIDOPERATION,它沒有幫助:) –