在我继续保存到数据库之前,我需要检查一些事情。
如果我想将对象保存到数据库,我必须检查两件事:
如果其中一个要求失败,我想通知用户无法保存,因为条件1不符合,或条件2不符合或两个条件都不符合。
我应该创建一个名为Validate()
的方法并将文本消息放入return参数吗?像
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;
}
然后我必须调用这两种方法,并且在调用代码中我必须设置要向用户显示的消息。
我不知道应该采用哪种方式处理这种情况。这种情况有最好的做法吗?
答案 0 :(得分: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'
}
}
您可以返回错误对象而不是字符串。
答案 1 :(得分:1)
对于像Validate这样的通用方法,我宁愿返回collection
。
通常,如果我们谈论业务对象,则需要对其数据的各个方面进行多次验证。因此,验证应该返回一个集合,其中列出了遇到的所有错误。
调用者总是可以遍历集合,然后决定如何处理它。
虽然您可以根据自己的需要返回list<string>
,但您可以考虑让custom object collection
返回MessageCollection
。这是因为有时候还会有其他数据要发回:例如:不同类型的错误类别/警告v / s错误等,或者OR条件等。
此外,根据是否需要对错误消息进行国际化,最好只返回实际业务对象中的错误代码,并让UI将其映射到正确的语言中,并以正确的语言为基础。用户的设置。
答案 2 :(得分:0)
第一个实施是维护噩梦。所有“客户端”代码都取决于你整合东西的方式。
第二个也不是首选;你将获得大量的公共方法来进行验证。
一个好的做法是将域逻辑作为POCO样式:创建一个保存所需信息状态的对象。让对象从具有通用验证方法的基类派生。让每个特定对象覆盖validate方法,并执行与该对象属性相关的一些特定验证。让每个验证方法在字符串列表中输出错误消息,例如List或IQueryable。
答案 3 :(得分:0)
我要么定义一个自定义的返回类型(消息集合),这是一个干净的解决方案。
或者作为一个快速的hackish解决方案返回一个bool并使用out参数输出附加信息。
bool Validate(out string[] messages)
{
...
}
bool Validate()
{
string[] messages;
return Validate(messages);
}
答案 4 :(得分:0)
我会使用现有的验证框架而不是自己做。
答案 5 :(得分:0)
在之前的项目中,我们有一个ValidationResult
类。
public class ValidationResult
{
public bool Success;
public string Message;
}
这提供了一个简单的机制,用于返回验证是否成功以及发生相应的失败消息。如果我们的结果需要更多信息,我们只需继承ValidationResult并以这种方式扩展类。
答案 6 :(得分:0)
在要验证的对象上实现IDataErrorInfo,该接口允许收集由属性名称键入的错误消息。
它还有一个名为Error的字符串属性,它可以表示整个对象的单个错误。
答案 7 :(得分:0)
以下是我如何做到这一点......
我有一个通用的返回类型
public class ValidatorResult
{
public ValidatorResult()
{
this.Failiures = new List<string>();
}
public bool IsValid => !this.Failiures.Any();
public List<string> Failiures { get; set; }
}
我创建了一个定义我的支票的界面......
public interface ISalesOrderValidator
{
ValidatorResult ValidateParams(CreateSalesOrderParams obj);
ValidatorResult ValidateParams(UpdateSalesOrderParams obj);
ValidatorResult ValidateParams(ApplyDiscountParams obj);
}
...和基类......
public class BaseValidator
{
public BaseValidator()
{
this.ValidatorResult = new ValidatorResult();
}
public ValidatorResult ValidatorResult { get; set; }
}
然后我实现了我的界面...
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();
}
}
然后,在我需要进行检查的代码中,我调用了验证器......
// 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)
{
}
}