2009-01-23 68 views
2

這是驗證傳遞給函數,即輸入的最佳方式做您驗證所有輸入出發某些東西一樣編碼風格 - 輸入驗證

class A; 
void fun(A* p) 
{ 
    if(! p) 
    { 
    return; 
    } 

B* pB = p->getB(); 
    if(! pB) 
    { 
    return; 
    } 

....... 

} 

之前還是你寫這樣的:

void fun(A* p) 
{ 
    if(p) 
    { 
    B* pB = p->getB(); 
    if(pB) 
    { 
     ..... 
    } 
    } 
} 

我在問這是因爲,如果我使用第一種風格,那麼我的代碼中會有多個返回語句,很多人都說不好(不知道爲什麼),如果使用第二種風格,那麼會有在我的代碼中嵌套層次太多。

回答

1

我喜歡做我輸入驗證前期,但往往會一次性進行測試

if(!p || !p->getB()){ 
    return; 
} 

如果功能操作輸入是必需的,並且語言支持它,我拋出了參數異常(請參閱.NET ArgumentNullException,ArgumentException),以便在無效狀態下代碼不會執行乾淨的返回。這讓調用者知道參數不足以完成操作。

+0

這與NullPointerException有何不同? – Arkadiy 2009-01-23 20:02:41

+0

輸入先決條件不限於指針非空的情況 – 2009-01-26 16:01:52

7

第一種方式比第二種方式更容易閱讀,且複雜程度較低(深度)。在第二種情況下,隨着參數數量的增加,複雜性和深度會增加。但在第一個例子中,它只是線性的。

+1

說多個回報不好的人是'結構化編程'嬉皮士。假設有多個返回語句會導致代碼難以閱讀。我認爲這個例子突出了事實,這並非總是如此。 – paxos1977 2009-01-24 03:06:44

0

理想情況下,你會通過引用傳遞,然後你不必擔心這一點。但這並不總是一種選擇。否則,這是一個偏好問題。

我個人更喜歡第一個,因爲我沒有多少回報問題。我認爲函數應該基本適合一個或兩個屏幕,所以只要你有語法突出顯示它不應該很難看到一個函數的所有退出點。

0

我用您發佈的第一種方法,這讓我在大多數情況下,提供兩種:meaningfull返回值或消息給用戶:


btnNext_OnClick(...) 
{ 
if(!ValidateData()) 
return; 

// do things here 
} 


boolean ValidateData() 
{ 
if(!condition) 
{ 
MessageBox.Show("Message", "Title", MessageBoxButtons.OK, MessageBoxIcons.Information); 
return false; 
} 

return true; 
} 

這樣一來,當我添加一個字段,需要表單級別驗證,我可以添加另一個if語句檢查驗證方法。

1

我更喜歡第一個,我有一組宏處理常見情況(通常爲了調試目的同時斷言)。這種方法的缺點是你的函數返回類型必須相當統一,以使你的宏使用統一;好處是使用/效果非常明顯。因此,例如,我的代碼可能會顯示爲:

class A; 
void fun(A* p) 
{ 
    ASSERT_NONZERO_RETURN_ON_FAIL(p); 

    B* pB = p->getB(); 
    ASSERT_NONZERO_RETURN_ON_FAIL(pB); 

    ....... 
} 

這會產生更多可讀代碼,這些代碼還會提醒您錯誤。此外,作爲額外的好處,如果您發現重視運行時檢查值的邊際速度增加,您可以輕鬆禁用檢入發佈版本。

補充說明:根據我的經驗,有些人說從函數返回多個點的原因很糟糕,因爲他們在函數退出之前顯式地進行資源解除分配,因此你不想重複去分配碼。但是,如果您正確且一致地使用RIIA,這不應該成爲問題。由於這是我試圖總是這樣做的,所以多個返回點比我更適合嵌套。

4

多重回報:人員和編碼標準都是雙向的。在C++中,如果使用RAII等,沒有理由不喜歡多個返回(和異常)。許多C編碼標準強制執行單入單出,以確保所有清理代碼得到執行,因爲沒有RAII和基於範圍的銷燬/資源清理。

Should a function have only one return statement?

1

我傾向於在該方法的開始使用這些類型檢查並返回的。 這樣在 Bertrand Meyer'sObject-Oriented Software Construction, second edition, Prentice Hall描述我有點效仿 Eiffeldesign by contractpreconditionsassertions, 。

對於你的榜樣,而不是返回無效,我將返回 枚舉識別違反類似:

enum Violation { inviolate = 0, p_unspecified_unavailable, p_B_unspecified_unavailable,..... }; 

Violation fun(A* p) 
{ 
//__Preconditions:___________________________________ 
    if (! p)   return p_unspecified_unavailable: 
    if (! p->getB()) return pB_unspecified_unavailable; 
//__Body:____________________________________________ 
    .... 
//__Postconditions: _________________________________ 
    ..(if any).. 
    return inviolate; 
} 

我的意思是說,我考慮的前提條件(和任何職位條件)驗證 到是圍繞方法/函數主體的實現的一種包裝,並傾向於區分和分離控制條件邏輯與主體表達的流程。