2012-04-19 55 views
0

我只想知道你在哪裏定義,拋出和捕獲異常以及看看是否有共識關於做考慮。設計異常,使用和定義

讓我來說一個基於的例子。 讓我說我有解決方案,並在該解決方案,我有2個項目:DomainProjectControllerProject

  1. 在DomainProject我有做一些查詢例如在RepositoryClass存儲庫我的方法:

    GetObjectById(int id) { ... } 
    

    而且我有一些例外情況在這個項目像ObjectNotFoundException定義。

  2. ControllerProject我想查詢我的倉庫,所以我做的東西,看起來像:

    MyObject obj = repo.GetObjectById(11); 
    

現在的問題是,如果ID的確存在誰應該檢查的照顧。如果你選擇的是ControllerProject應檢查ID的存在,你可以用一些這樣的代碼結束:

MyObject obj = repo.GetObjectById(11); 
if (obj == null) {throw new ObjectNotFoundException();} 

但是那不好的一面是,它往往是重複的遍在的地方GetObjectById用來。當然,在某些情況下,如果你得到一個空值,你不會在意,所以它不會直接在DomainProject中拋出異常。但我首先不喜歡重複if測試,其次,更多與我的問題有關,我不喜歡在當前項目之外使用異常定義。

我有這樣的感覺,一個異常只應該扔在項目中,它是定義和其他項目應該只抓住他們。

回到我的例子,我將如何解決這種情況。那麼一個簡單的想法是在我的域項目中定義2方法。一個拋出異常,另一個拋出異常。唯一不確定的是我必須使用哪種命名約定:GetObjectByIdThrowsIfNotFound()GetObjectById()。或者,我可以添加一個可選參數GetObjectById(int id, bool isExceptionThrow = true)

您如何看待異常?

感謝

回答

2

我認爲你正在考慮如何讓你的設計能夠正確地傳達意圖是件好事。我同意你的疑慮:拋出異常的唯一層應該是定義異常的層。

也就是說,如果空返回值不明確,您只需要一個異常拋出變體,如果它有效將一個關鍵字與null相關聯。如果沒有(並且這應該在您的XML註釋中註明!),那麼null返回總是意味着同樣的事情(未找到值),您可以節省自己的代碼並在Domain層中處理異常的開銷。如果'找不到值'在Controller層中是一個非常特殊的事件,那麼定義並拋出異常。

如果「存儲null有效,我用IDictionary<T>建立的語義模式:bool TryGetObjectById(int id, out object value),我只包括一個異常拋出GetObjectById(int key)變種如果鑰匙未找到的是真正的無與倫比的,我想以節省在路上調用Try...變體所涉及的擊鍵。

+0

試試..似乎是一個很好的建立模式謝謝你的答案。但是,而不是一個out對象的值,我寧願有一個lambda,它只會在沒有找到對象時調用。 – mathk 2012-04-19 16:15:38

+0

@mathk:我認爲自己是lambdas的一個*大*粉絲 - 我使用Autofac! - 但有趣的是,似乎爲了lambda而使用lambda表達式。另一個例子可能會影響我,但是'if(TryGetX(id,out val)){yes ...;} else {no ...;}'比'var val = GetXElse(id,()= > {no ...;});如果(???){yes ...;}',甚至將後者中的內容擱置一邊if(???)'。但是,如果你喜歡它,那麼基本的觀點仍然存在:如果'null'返回不明確,你只需要變體。如果你不需要它們,包括它們會混淆你的意圖。 – 2012-04-19 16:38:38

0

有兩種模式我經常看到:

1)倉庫本身應該拋出異常,如果你要處理的故障您的調用方法應該在try/catch塊包裹獲取物品。我認爲這種模式將成爲您的應用程序的主要候選者,因爲調用者有責任處理異常。我會假設你的版本庫不會捕獲SqlException或任何持久層異常被拋出正確的?如果是這樣,那麼你應該讓存儲庫拋出異常並讓它冒出堆棧。

如果不是....

2)你暴露包裹在一個容器中的對象,告訴你的失敗或成功:

public class RepositoryItemContainer<DataType> 
{ 
    public DataType Object { get; set; } 
    public bool WasFound { get; set; } 
} 

然後,而不是隻返回值,返回這個包裝,然後將代碼可以決定什麼要做到:

var repoItem = _repo.GetObjectById(11); 

if(repoItem.WasFound) 
    var item = repoItem.Object; 

else 
    throw new ApplicationSpecificException("Wasnt found yo!") 
0

這裏僅僅是幾個方面的考慮:

  1. Exceptions用於例外情況。因此,如果您認爲數據庫中沒有對象是例外的情況,那麼我現在就要按照您現在實施的方式行事。

  2. 如果不是特殊情況,在某種程度上實現的方法,它並沒有提高和Exception,但返回null,在情況下,我們對遺漏查詢id,自然。看起來很自然,並保持開發人員的預期行爲,這些開發人員將使用您實施的回購類。

  3. 您可以添加一種ContainsId(long id)方法,首先檢查數據庫中是否存在需求id。可能是一個不錯的選擇,但我個人更喜歡第二點。

希望這會有所幫助。