C# 对象验证器-这个设计好吗?

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

我正在从事一个项目,我编写的API方法必须返回域对象的不同“视图”,如下所示:

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验证块或从中获得一些灵感