2010-10-14 53 views
1

我有一種情況,在繼續保存到數據庫之前,需要檢查幾件事情。C#驗證方法,可以返回多條消息

如果我要救的對象我有數據庫來檢查兩件事情:

  1. 是否所有所需的東西填充?
  2. 已經有一個具有相同地位的東西?

如果其中一項要求失敗,我想通知用戶由於條件1未滿足,或者條件2不符合或兩個條件都不符合,所以無法保存。

我應該只是創建一個名爲Validate()的方法,並將文本消息放入返回參數?類似於

public string Validate() 
{ 
    string message = string.Empty; 

    if(! /*Do some validating for 1) */) 
    message = "Condition 1 not met"; 
    if(! /*Do some validating for 2) */) 
    message += Environment.NewLine + "Condition 2 not met!"; // 

    return message; 
} 

然後在調用代碼中檢查message是否爲空。這是一個好方法嗎?

我也一直在想兩種方法。但是,我必須在任何想要將對象保存到數據庫的地方調用這兩個方法。這樣我就重複了我自己。這樣,你得到的東西是這樣的:

public bool AreRequiredThingsFilled() 
{ 
    if(/* do something*/) 
    return true; 

    return false; 
} 

public bool CheckStatus() 
{ 
    if(/* do something*/) 
    return true; 

    return false; 
}  

然後我打電話給這兩種方法,並在調用代碼我必須設置我要顯示給用戶的消息。

我不知道該如何處理這種情況。對於這種情況是否有最佳做法?

回答

4

我以前見過的一個有趣的模式是返回IEnumerable消息。

public bool HasValidationErrors() 
{ 
    return GetValidationErrors().Any(); 
} 

public IEnumerable<string> GetValidationErrors() 
{ 
    if (/* Some Condition */) 
    { 
     yield return "condition 1 not met"; 
    } 

    if (/* Some Condition */) 
    { 
     yield return "condition 2 not met"; 
    } 

    yield break; 
} 

然後在你的代碼,你會怎麼做:

if (HasValidationErrors()) 
{ 
    foreach (string error in GetValidationErrors()) 
    { 
     // Do something with 'error' 
    } 
} 

你可以返回,而不是當然的字符串錯誤對象。

+0

假設在一次使用上面的代碼時,所有條件都不符合(即所有的yield都被命中),那麼在使用代碼中的'HasValidationErrors()'中的'.Any塊導致第一個'if()'再次產生'yield',即最終在IEnumerable中有3個項目。 – 2012-02-03 15:33:25

1

如果使用Validate等通用方法,我寧願返回collection

通常,如果我們談論的是Business object,那麼將需要對其數據的各個方面進行多重驗證。因此,驗證應該返回一個集合,並列出所有遇到的錯誤。

調用者可以始終循環訪問集合,然後決定如何處理它。

雖然您可以根據自己的需要返回list<string>,但可以考慮讓custom object collection返回,例如MessageCollection。這是因爲有時需要發送額外的數據,例如:不同類型的錯誤類別/警告或錯誤等,或者條件等。

另外,根據是否需要國際化錯誤消息,最好從實際的業務對象中返回一個錯誤代碼,然後讓UI根據用戶的設置以正確的語言將其映射到正確的錯誤消息。

0

第一個實現是維護噩夢。所有的「客戶端」代碼都取決於你分析東西的方式。

第二也不是優選;你會得到大量的公共方法來驗證將來。

一個好的做法是將領域邏輯作爲一種POCO風格:創建一個對象來保存您將需要的信息狀態。讓對象從基類中派生出一個通用的驗證方法。讓每個特定的對象重寫validate方法,並做一些與該對象的屬性相關的特定驗證內容。讓每個驗證方法在字符串列表中抽取它們的錯誤消息,例如List或IQueryable。

+0

你有一點樣品代碼?或者更詳細地解釋這一點的鏈接? – Martijn 2010-10-14 10:35:58

0

我要麼定義一個自定義返回類型(消息收集)這是乾淨的解決方案。

或者作爲一個快速hackish解決方案返回一個布爾和使用出參數輸出額外的信息。

bool Validate(out string[] messages) 
{ 
    ... 
} 

bool Validate() 
{ 
    string[] messages; 
    return Validate(messages); 
} 
0

我會使用現有的驗證框架,而不是自己做。

0

在之前的項目中,我們有一個ValidationResult類。

public class ValidationResult 
{ 
    public bool Success; 
    public string Message; 
} 

這提供了一個簡單的機制來返回驗證是否成功以及是否發生相應的失敗消息。如果我們的結果需要更多信息,我們只需從ValidationResult繼承並以這種方式擴展類。

0

在要驗證的對象上實現IDataErrorInfo,該接口允許按屬性名稱收集錯誤消息。

它也有一個名爲Error的字符串屬性,它可以表示整個對象的單個錯誤。

0

這是我怎麼會做這個...

  1. 我有一個通用的返回類型

    public class ValidatorResult 
    { 
        public ValidatorResult() 
        { 
         this.Failiures = new List<string>(); 
        } 
    
        public bool IsValid => !this.Failiures.Any(); 
    
        public List<string> Failiures { get; set; } 
    } 
    
  2. 我創建定義我的支票接口...

    public interface ISalesOrderValidator 
    { 
        ValidatorResult ValidateParams(CreateSalesOrderParams obj); 
    
        ValidatorResult ValidateParams(UpdateSalesOrderParams obj); 
    
        ValidatorResult ValidateParams(ApplyDiscountParams obj); 
    } 
    
  3. ...和一個基類...

    public class BaseValidator 
    { 
        public BaseValidator() 
        { 
         this.ValidatorResult = new ValidatorResult(); 
        } 
    
        public ValidatorResult ValidatorResult { get; set; } 
    } 
    
  4. 然後我實現我的接口...

    public class SalesOrderValidator : BaseValidator, ISalesOrderValidator 
    { 
        ValidatorResult ValidateParams(CreateSalesOrderParams obj) 
        { 
         try 
         { 
          if (obj.Payee == null) 
           ValidatorResult.Failiures.Add("You must proivde a Payee"); 
    
          if (obj.PaymentAmount == 0) 
           ValidatorResult.Failiures.Add("PaymentAmount is 0");     
         } 
         catch (Exception) 
         { 
          ValidatorResult.Failiures.Add("An unexpected error occurred."); 
         } 
    
         return base.ValidatorResult; 
        } 
    
        ValidatorResult ValidateParams(UpdateSalesOrderParams obj) 
        { 
         throw new NotImplementedException(); 
        } 
    
        ValidatorResult ValidateParams(ApplyDiscountParams obj); 
        { 
         throw new NotImplementedException(); 
        } 
    } 
    
  5. 然後,我的代碼中,我需要做檢查,我把我的驗證......

    // start by doing some basic validation on the parameters 
    var validationResult = _validator.ValidateParams(mySalesOrder); 
    if (!validationResult.IsValid) 
        throw new ValidationException(validationResult.Failiures.FirstOrDefault()); 
    

...這只是返回第一個錯誤 - 您可以更改代碼以返回多個錯誤消息或錯誤堆棧(內部異常)。 注 - ValidationException定義如下...

public class ValidationException : ApplicationException 
    { 
     public ValidationException() 
     { 
     } 

     public ValidationException(string message) 
      : base(message) 
     { 
     } 

     public ValidationException(string message, Exception inner) 
      : base(message, inner) 
     { 
     } 
    }