2009-06-25 60 views
8

我有一個Employee類。我希望能夠在保存它之前驗證它(),以確保所有字段都填充了有效值。 類的用戶可能在調用Save()之前調用Validate(),或者直接調用Save(),然後Save()將調用Validate(),如果驗證失敗可能會拋出異常。從驗證功能回覆額外信息的最佳做法

現在,我的(主要)問題是這樣的;
如果我的Validate()函數返回一個簡單的布爾值,那麼我該如何告訴該類的用戶什麼是錯誤的,即「電子郵件沒有填充」,「ID不唯一」等。爲了這個目的,我只想錯誤字符串傳遞給人類用戶,但如果我想要一個錯誤代碼列表(除了使位圖更符合邏輯),原理是相同的。

  • 我可以在我的驗證功能中使用一個參數,但我明白這是皺眉。
  • 而不是返回一個布爾,我可以從我的函數返回一個字符串數組,並只是測試它是否爲空(意思是沒有錯誤) - 但這似乎凌亂,不正確。
  • 我可以創建一個Struct來返回此方法,包括一個bool和一個帶錯誤消息的字符串數組,但看起來很笨重。
  • 我可以返回一個錯誤代碼而不是一個布爾的位圖並查找它,但這似乎相當過分。
  • 我可以在容納錯誤的對象上創建一個公共屬性「ValidationErrors」。然而,這要依賴我在讀取之前調用Validate(),或者從Property()明確調用Validate,這有點浪費。

我的具體程序是在C#中,但這看起來像一個相當通用的「最佳實踐」的問題,我相信我應該知道答案。任何建議感激地收到。

回答

5

我可能會去的位圖選項。只要

[Flags] 
public enum ValidationError { 
    None = 0, 
    SomeError = 1, 
    OtherError = 2, 
    ThirdError = 4 
} 

...並調用代碼,簡單地說:

ValidationError errCode = employee.Validate(); 
if(errCode != ValidationError.None) { 
    // Do something 
} 

看上去不錯,緊湊到我。

+0

+1 - 你打敗了我。 – 2009-06-25 12:21:43

+0

你是對的,我應該對我的錯誤消息進行構建,併爲他們建立一箇中央存儲庫,在那裏我可以查找他們的「用戶友好」版本等。 – Frans 2009-06-25 15:10:47

6

我可以創建一個Struct來返回這個方法,包括一個bool和一個帶有錯誤信息的字符串數組,但看起來很笨重。

爲什麼它看起來笨重?創建一個合適的類型來封裝信息是完美的。不過,我不一定使用字符串來編碼這些信息。枚舉可能更適合。

另一種方法是對返回類型進行子類化併爲每個案例提供一個額外的子類 - 如果適用的話。如果可能發出多個故障信號,則陣列可以正常工作。但是我也將它封裝在自己的類型中。

一般模式看起來是這樣的:

class ValidationInfo { 
    public bool Valid { get; private set; } 
    public IEnumerable<Failure> Failures { get; private set; } 
} 
1

我將遵循的的TryParse方法的模式和使用方法與此簽名:

public bool TryValidate(out IEnumerable<string> errors) { ... } 

另一種選擇就是拉驗證將對象編碼到它自己的類中,可能建立在規範模式上。

public class EmployeeValidator 
{ 
    public bool IsSatisfiedBy(Employee candidate) 
    { 
     //validate and populate Errors 
    } 
    public IEnumerable<string> Errors { get; private set; } 
} 
0

我們使用彈簧驗證與Windows窗體錯誤提供程序一起使用。

所以我們的驗證函數返回一個控件ID和錯誤消息(每個校驗錯誤)一本字典。錯誤提供程序在導致錯誤的控件附近的彈出字段中顯示錯誤消息。

我使用了一些其他驗證方案在過去的 - 但這個作品真的很好。

1

我已經發現這是一個很好的方法來簡單地有一個方法(或屬性,因爲C#有那該多好支持),返回某種合理的所有驗證錯誤消息,易於使用的格式,如清單的字符串。

這種方式,您也可以讓你的validate方法返回的bool。

2

聽起來像是你需要一個泛型類:

public sealed class ValidationResult<T> 
{ 
    private readonly bool _valid; // could do an enum {Invalid, Warning, Valid} 
    private readonly T _result; 
    private readonly List<ValidationMessage> _messages; 

    public ValidationResult(T result) { _valid = true; _result = result; _messages = /* empty list */; } 

    public static ValidationResult<T> Error(IEnumerable<ValidationMessage> messages) 
    { 
     _valid = false; 
     _result = default(T); 
     _messages = messages.ToList(); 
    } 

    public bool IsValid { get { return _valid; } } 
    public T Result { get { if(!_valid) throw new InvalidOperationException(); return _result; } } 
    public IEnumerable<ValidationMessage> Messages { get { return _messages; } } // or ReadOnlyCollection<ValidationMessage> might be better return type 

    // desirable things: implicit conversion from T 
    // an overload for the Error factory method that takes params ValidationMessage[] 
    // whatever other goodies you want 
    // DataContract, Serializable attributes to make this go over the wire 
} 
1

你可以看看羅克福德Lhotka的里昂證券,其中有廣泛的業務規則/驗證跟蹤FORR業務對象。

www.lhotka.net

1

我與克里斯W.同意我問同樣的問題,閱讀Rocky`s專家C#業務對象之前。

他的裝卸業務驗證規則輝煌之路。驗證在每個屬性設置完成後完成。每當規則被破壞時,對象的狀態就變爲無效。

您的業務類可以實現IDataError接口。將您的UI控件綁定到您的業務對象屬性然後會通知您的ErrorProvider控件對象上的任何損壞的規則。

我真的建議你花時間看看驗證部分。