Jacek
Jacek

Reputation: 12053

Validating by attribute

I would like to check by attribute that value passed to method is correct, because adding if condition to method body make code less readable (in my opinion)

For example,

    public object GetSomething(int id)
    {
        // there could be more conditions
        if (id<= 0)
            throw new ArgumentOutOfRangeException(nameof(id), $"Forbiden value: '{id}'");
        // real logic
        ...

I want to check it is such way

    [PossitiveValueAttr(id)]
    public object GetSomething(int id)
    {
        // real logic

or (I would prefer that)

    public object GetSomething([PossitiveValueAttr] int id)
    {
        // real logic

1) Do you know any similar existing solution?

2) How can I pass method's argument to my attribute?

Upvotes: 0

Views: 64

Answers (2)

Dylan Nicholson
Dylan Nicholson

Reputation: 1368

Inspired by Manfred...

So if for any method defined as

void DoSomething([Attr1] Type1 param1, [Attr2] Type2 param2, ...)
{
}

You're happy to add as the first statement of the method:

Validate(() => DoSomething(param1, param2, ...)) 

Where Attr1/Attr2 etc. all implement ValidationAttribute:

[AttributeUsage(AttributeTargets.Parameter)]
public class ArgumentAttribute : Attribute
{
    public void Validate(string argumentName, object value)
    {
        // throw exception if not valid
    }
}

Then you can implement Validate as:

static void Validate(Expression<Action> expr)
{
    var body = (MethodCallExpression)expr.Body;

    foreach (MemberExpression a in body.Arguments)
    {
        FieldInfo fi = a.Member as FieldInfo;
        ParameterInfo pi = body.Method.GetParameters().FirstOrDefault(p => p.Name == fi.Name);
        ValidationAttribute va = pi?.GetCustomAttribute<ValidationAttribute>();
        if (va != null)
            va.Validate(pi.Name, fi.GetValue(((ConstantExpression)a.Expression).Value));
    }
}

And use it generically wherever you need to perform argument validation defined via custom attributes.

The main drawback is that ValidationAttribute can't be generic, so you always get a plain 'object' passed in that you'll have to downcast.

Upvotes: 1

Dylan Nicholson
Dylan Nicholson

Reputation: 1368

Attributes can't magically cause any behavioral change in your application unless you have code that looks for and acts on them. Further, attributes can only be determined if you have reflection information, which you can't get for function arguments. But for your particular example (must be positive), why not just used an unsigned int?

Upvotes: 0

Related Questions