2012-10-15 90 views
2

我正在編寫使用第三方庫處理某些數據的應用程序。在非常簡單的例子,我有運行作爲這樣的任務的方法:阻止代碼並等待事件處理程序觸發?

private void ProcessListOfItems(List<string> items) 
{ 
    while (items.Count > 0) 
    { 
     3rdPartyLibObject.Process(items[0]); 
     items.Remove(0); 
    } 
} 

正如你看到的,我的代碼目前正在編寫方式,我從列表中儘快刪除每個項目的工藝路線()方法返回。但是,某件物品的處理可能會失敗,我需要知道這是否會發生。不幸的是,Process()方法不會返回一個bool值來指示該項目是否成功處理,而是會觸發ProcessingComplete和ProcessingFailed事件。我迷上了這些事件,這樣的事件處理程序:

3rdPartyLibObject.ProcessingComplete += obj_ProcessingSuccess; 
3rdPartyLibObject.ProcessingFailed += obj_ProcessingFailed; 

private void obj_ProcessingSuccess(object sender, 3rdPartyLibObject.ProcessingEventArgs e) 
{ 
    this.Invoke(new ProcessedHandler(OnProcessed), new object[] { true }); 
} 

private void obj_ProcessingFailed(object sender, 3rdPartyLibObject.ProcessingEventArgs e) 
{ 
    this.Invoke(new ProcessedHandler(OnProcessed), new object[] { false }); 
} 

private void OnProcessed(bool success) 
{ 
    if (success) 
    { 
     Debug.WriteLine("Item was processed succesfully!"); 
    } 
    else 
    { 
     Debug.WriteLine("Failed to process item!"); 
    } 
} 

我想什麼做的是有我的代碼塊中調用3rdPartyLibObject.Process(後右),直至事件處理程序火災這樣的一個我知道該項目是否無法處理(以及我是否應該從列表中刪除它)。我猜這可能不是一個不常見的情況,但我從來沒有遇到過它。處理這種情況有沒有普遍認同的最佳做法?

+0

爲什麼不將您的物品刪除代碼添加到OnProcessed方法中?顯然這需要跟蹤哪個項目正在處理,但這是我能看到的最簡單的解決方案。 –

+0

班上的布爾場無法解決。 –

回答

11

個人而言,我把這個包成Task<bool>,像這樣:

Task<bool> Process3rdParty(ThirdPartyLibObject thirdParty, string item) 
{ 
    var tcs = new TaskCompletionSource<bool>(); 

    thirdParty.ProcessingComplete += (o, e) => tcs.SetResult(true); 
    thirdParty.ProcessingFailed += (o, e) => tcs.SetResult(false); 

    thirdParty.Process(item); 

    return tcs.Task; 
} 

然後,您可以調用這個像這樣:

private void ProcessListOfItems(List<string> items) 
{ 
    while (items.Count > 0) 
    { 
     var task = Process3rdParty(thirdPartyLibObject.Process(items[0]); 
     if (task.Result) 
      items.Remove(0); 
    } 
} 

這也將簡化事情,如果你決定,以後,您希望它異步運行或一次處理多個項目(如果第三方庫支持)。這對於轉移到C#5的異步/等待支持以使整個事物異步來說也是非常簡單的。

+0

難道你不想使用'TrySetResult'而不是'SetResult',因爲兩者之一會失敗。 – Servy

+0

@Servy如果兩個中只有一個會被調用(這是OP建議的),那麼'SetResult'應該沒問題。如果兩個事件都可能發生在同一個實例上,那麼'TrySetResult'會更好。 –

+0

@ReedCopsey如何將此模式重構爲異步/等待C#5? – Arvis

1

將這項工作:

private bool itemProcessed = false; 

private void ProcessListOfItems(List<string> items) 
{ 
    while (items.Count > 0) 
    { 
     3rdPartyLibObject.Process(items[0]); 
     if (itemProcessed) 
     { 
      items.Remove(0); 
     } 
    } 
} 

private void obj_ProcessingSuccess(object sender, 3rdPartyLibObject.ProcessingEventArgs e) 
{ 
    this.itemProcessed = true; 
} 

private void obj_ProcessingFailed(object sender, 3rdPartyLibObject.ProcessingEventArgs e) 
{ 
    this.itemProcessed = false; 
} 

假設事件在同一線程上的所有火,處理應該處理你的下一個項目之前調用。

+1

感謝您的建議!儘管我最終選擇了另一個答案來解答我的問題,但我很欣賞你的想法以及你提出建議的時間! – user685869

相關問題