如何在.NETFramework3.5中使用数据注释对C#类进行属性验证

本文关键字:验证 属性 注释 数据 NETFramework3 | 更新日期: 2023-09-27 18:19:41

在.NET Framework中有没有一种方法可以将类用数据注释修饰的对象实例交给某个方法或验证器,并接收错误集合?

我知道在.NET 4.x中有一种方法可以做到这一点。但是在.NET 3.5中有类似的机制吗?

如何在.NETFramework3.5中使用数据注释对C#类进行属性验证

通过一点反射,您可以构建自己的验证器,扫描您所拥有的属性上的ValidationAttributes。这可能不是一个完美的解决方案,但如果您仅限于使用.NET 3.5,那么这似乎是一个轻量级的解决方案。

static void Main(string[] args)
{
    Person p = new Person();
    p.Age = 4;
    var results = Validator.Validate(p);
    results.ToList().ForEach(error => Console.WriteLine(error));
    Console.Read();
}       
// Simple Validator class
public static class Validator
{
    // This could return a ValidationResult object etc
    public static IEnumerable<string> Validate(object o)
    {
        Type type = o.GetType();
        PropertyInfo[] properties = type.GetProperties();
        Type attrType = typeof (ValidationAttribute);
        foreach (var propertyInfo in properties)
        {
            object[] customAttributes = propertyInfo.GetCustomAttributes(attrType, inherit: true);
            foreach (var customAttribute in customAttributes)
            {
                var validationAttribute = (ValidationAttribute)customAttribute;
                bool isValid = validationAttribute.IsValid(propertyInfo.GetValue(o, BindingFlags.GetProperty, null, null, null));
                if (!isValid)
                {
                    yield return validationAttribute.ErrorMessage;
                }
            }
        }
    }
}
public class Person
{
    [Required(ErrorMessage = "Name is required!")]
    public string Name { get; set; }
    [Range(5, 20, ErrorMessage = "Must be between 5 and 20!")]
    public int Age { get; set; }
}

这会将以下内容打印到控制台:

姓名是必填项
必须介于5和20之间!

Linq版本

public static class Validator
{
    public static IEnumerable<string> Validate(object o)
        {
            return TypeDescriptor
                .GetProperties(o.GetType())
                .Cast<PropertyDescriptor>()
                .SelectMany(pd => pd.Attributes.OfType<ValidationAttribute>()
                                    .Where(va => !va.IsValid(pd.GetValue(o))))
                                    .Select(xx => xx.ErrorMessage);
        }
    }

这些数据注释主要在另一个框架的上下文中工作,例如MVC w/Razor、Fluent等。如果没有其他框架,注释就是标记代码,需要一个框架/额外的代码来进行解释。

注释本身并不是真正的AOP/Intercept,因此注释在用注释修饰的对象提交给知道如何解释/解析标记代码的中间框架(通常通过.reflection)之前什么都不做。

对于真正的AoP,它可以使注释本质上起作用,你需要PostSharp/Unity等。这些框架在运行/编译时修改IL,并重新路由原始代码。