C# 对象验证器-这个设计好吗?
我正在从事一个项目,我编写的API方法必须返回域对象的不同“视图”,如下所示:C# 对象验证器-这个设计好吗?,c#,validation,reflection,attributes,C#,Validation,Reflection,Attributes,我正在从事一个项目,我编写的API方法必须返回域对象的不同“视图”,如下所示: namespace View.Product { public class SearchResult : View { public string Name { get; set; } public decimal Price { get; set; } } public class Profile : View { publi
namespace View.Product
{
public class SearchResult : View
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public class Profile : View
{
public string Name { get; set; }
public decimal Price { get; set; }
[UseValidationRuleset("FreeText")]
public string Description { get; set; }
[SuppressValidation]
public string Comment { get; set; }
}
}
这些也是API中setter方法的参数,在将它们存储到DB中之前必须对其进行验证。我编写了一个对象验证器,允许用户在XML文件中定义验证规则集,并检查对象是否符合这些规则:
[Validatable]
public class View
{
[SuppressValidation]
public ValidationError[] ValidationErrors
{
get { return Validator.Validate(this); }
}
}
public static class Validator
{
private static Dictionary<string, Ruleset> Rulesets;
static Validator()
{
// read rulesets from xml
}
public static ValidationError[] Validate(object obj)
{
// check if obj is decorated with ValidatableAttribute
// if not, return an empty array (successful validation)
// iterate over the properties of obj
// - if the property is decorated with SuppressValidationAttribute,
// continue
// - if it is decorated with UseValidationRulesetAttribute,
// use the ruleset specified to call
// Validate(object value, string rulesetName, string FieldName)
// - otherwise, get the name of the property using reflection and
// use that as the ruleset name
}
private static List<ValidationError> Validate(object obj, string fieldName, string rulesetName)
{
// check if the ruleset exists, if not, throw exception
// call the ruleset's Validate method and return the results
}
}
public class Ruleset
{
public Type Type { get; set; }
public Rule[] Rules { get; set; }
public List<ValidationError> Validate(object property, string propertyName)
{
// check if property is of type Type
// if not, throw exception
// iterate over the Rules and call their Validate methods
// return a list of their return values
}
}
public abstract class Rule
{
public Type Type { get; protected set; }
public abstract ValidationError Validate(object value, string propertyName);
}
public class StringRegexRule : Rule
{
public string Regex { get; set; }
public StringRegexRule()
{
Type = typeof(string);
}
public override ValidationError Validate(object value, string propertyName)
{
// see if Regex matches value and return
// null or a ValidationError
}
}
[可验证]
公共阶级观
{
[抑制验证]
公共验证错误[]验证错误
{
获取{return Validator.Validate(this);}
}
}
公共静态类验证器
{
私有静态字典规则集;
静态验证器()
{
//从xml读取规则集
}
公共静态验证错误[]验证(对象obj)
{
//检查obj是否用ValidatableAttribute修饰
//如果不是,则返回空数组(验证成功)
//迭代obj的属性
//-如果属性使用SuppressValidationAttribute修饰,
//继续
//-如果使用UseValidationRulesetAttribute修饰,
//使用指定的规则集调用
//验证(对象值、字符串规则集名称、字符串字段名称)
//-否则,使用反射和
//将其用作规则集名称
}
私有静态列表验证(对象obj、字符串字段名、字符串规则集名)
{
//检查规则集是否存在,如果不存在,则引发异常
//调用规则集的Validate方法并返回结果
}
}
公共类规则集
{
公共类型类型{get;set;}
公共规则[]规则{get;set;}
公共列表验证(对象属性、字符串属性名称)
{
//检查属性是否为类型
//如果不是,抛出异常
//迭代规则并调用它们的Validate方法
//返回其返回值的列表
}
}
公共抽象类规则
{
公共类型类型{get;protected set;}
公共抽象验证错误验证(对象值、字符串属性名称);
}
公共类StringRegexRule:规则
{
公共字符串正则表达式{get;set;}
公共StringRegexRule()
{
类型=类型(字符串);
}
公共覆盖验证错误验证(对象值,字符串属性名称)
{
//查看正则表达式是否与值匹配并返回
//null或ValidationError
}
}
呸。。。感谢您阅读所有这些。我已经实现了它,它工作得很好,我计划扩展它来验证IEnumerable字段和其他可验证的字段的内容
- 我特别关心的是,如果没有指定任何规则集,验证程序将尝试使用属性的名称作为规则集名称。(如果您不希望出现这种行为,可以使用
)这会使代码更不杂乱(无需在每个属性上使用[SuppressValidation]
),但它感觉不太对劲。我无法决定是糟糕还是可怕。你觉得怎么样[UseValidationRuleset(“某物”)]
- 欢迎对本设计的其他部分提出任何建议。我不是很有经验,我很感激任何帮助
- 另外,“可验证”是一个好名字吗?对我来说,这听起来很奇怪,但我不是以英语为母语的人
public interface IValidatable
{
ValidationError[] Validate(Rulesets ruleSets);
}
public class View : IValidatable
{
public ValidationError[] Validate(Rulesets ruleSets)
{
// do validate
}
}
public static class Validator
{
private static Rulesets _rulesets;
static Validator()
{
// read rulesets
}
public static ValidationError[] Validate(object obj)
{
IValidatable validObj = obj as IValidatable;
if (obj == null)
// not validatable
return new ValidationError[0];
return validObj.Validate(_rulesets);
}
}
我的建议是使用一个接口,而不是属性:
public interface IValidatable
{
ValidationError[] Validate(Rulesets ruleSets);
}
public class View : IValidatable
{
public ValidationError[] Validate(Rulesets ruleSets)
{
// do validate
}
}
public static class Validator
{
private static Rulesets _rulesets;
static Validator()
{
// read rulesets
}
public static ValidationError[] Validate(object obj)
{
IValidatable validObj = obj as IValidatable;
if (obj == null)
// not validatable
return new ValidationError[0];
return validObj.Validate(_rulesets);
}
}
值得一提的是,有很多框架使用属性来定义验证。您可能会使用Microsoft验证块,或者从中获得一些灵感,因为有很多框架使用属性来定义验证。您可能会使用Microsoft验证块或从中获得一些灵感