验证方法参数上的DataAnnotations

时间:2016-02-11 15:18:11

标签: c# data-annotations

数据注释属性如何与方法参数一起使用?我期待做这样的事情,但不会抛出异常。

private string TestValidate([StringLength(5)] string name = "Default: throw exception")
{
    ValidationContext context = new ValidationContext(name);
    Validator.ValidateObject(name, context);
    return name;
}

或者,我知道这会奏效。但是,这并没有使用属性约定的便利性。

private string TestValidate(string name = "Default: throw exception")
{
    ValidationContext context = new ValidationContext(name);
    Validator.ValidateValue(name, context, new[] { new StringLengthAttribute(5) });
        return name;
}

1 个答案:

答案 0 :(得分:0)

如果您想要修改代码,那么您可以使用一些反思(请参阅https://msdn.microsoft.com/en-us/library/system.reflection.parameterinfo.attributes(v=vs.110).aspx

您可以在类初始化时评估一次反射,但这就是反射代码的工作方式:

// NOTE: nameof() is a .NET 4.6 feature.  If you are using an older
// version of .NET, you'll have to write the string yourself.
MethodInfo method = GetType().GetMethod(nameof(TestValidate), typeof(string));
// NOTE: it's on you to validate this and use the version with binding flags for
// special cases like non-public and static methods

ParameterInfo parameter = method.GetParameters().First();
// This is shorthand: GetCustomAttributes returns object[], you'll have
// convert that properly and reference your customAttributes later
ValidationAttribute[] customAttributes = parameter.GetCustomAttributes(
        typeof(ValidationAttribute), true); // second parameter ignored

// At this point you can handle the rest of your validation
ValidationContext context = new ValidationContext(name);
Validator.ValidateValue(name, context, customAttributes);
    return name;

许多验证框架只是封装了获取验证属性所需的所有反射。注意:在这种情况下,我使用了ValidationAttribute的子类,而不是更具体的StringLengthAttribute。对GetCustomAttributes()的调用将返回扩展我们要求的基类的任何属性。这允许您完全更改方法上的属性并添加更多约束而无需更改代码。如果您评估多个参数或删除参数,则必须进行一些更改。

您可以使这一点更通用,因为您拥有特定MethodInfo对象时的代码通常是相同的。在这种情况下,我可能会做一些改变:

public static void Validate(MethodInfo method, params object[] values)
{
    ValidationContext context = new ValidationContext(method.Name);
    ParameterInfo[] parameters = method.GetParameters();

    for(int i = 0; i < Math.Min(parameters.Length, values.Length); i++)
    {
        // This is shorthand: GetCustomAttributes returns object[], you'll have
        // convert that properly and reference your customAttributes later
        ValidationAttribute[] customAttributes = parameter[i].GetCustomAttributes(
                typeof(ValidationAttribute), true); // second parameter ignored

        Validator.ValidateValue(values[i], context, customAttributes);
    }
}