如何使用.NET Framework 3.5中的数据注释对C#类进行属性验证?

9

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

我发现在.NET 4.x中有一种方法可以这样做。但是在.NET 3.5中是否有类似的机制?


2
我不知道.NET 3.5中是否有这样的东西,但如果你愿意使用另一个库,Microsoft的企业应用程序块包含一个验证应用程序块,其中包含一个Validator类,可以验证用DataAnnotations装饰的对象。 - Ibrahim Najjar
3个回答

12

稍加思考,你就可以建立自己的验证器,扫描你拥有的属性上的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之间!


是的。这是可行的,因为数据注释属性已经实现了一个IsValid方法。谢谢! - Robert Harvey

7

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);
        }
    }

0

那些数据注释的东西主要是在另一个框架中起作用,例如MVC w/ Razor,Fluent等。没有另一个框架,这些注释只是标记代码,并且需要框架/额外的代码来进行解释。

注释本身并不是真正的AOP /拦截,因此除非使用带有注释的对象提交到知道如何解释/解析标记代码的中介框架(通常通过反射),否则注释无效。

对于真正的AoP,可以使注释内在地工作,您将需要像PostSharp / Unity等类似的东西。这些框架在运行/编译时修改IL并重新路由原始代码。


数据不是来自UI,而是来自我无法控制的外部来源。如果不是这种情况,我可以直接使用Winforms或ASP.NET MVC提供的验证。我认为我不需要代码注入式AOP,请参见Patrick McGee的答案 - Robert Harvey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接