4

I've built up a simple ArgumentValidator class in order to simplify argument preconditions in any given method. Most of them are null or bounds checks and it gets pretty tedious after a couple of

if (arg == null ) throw new ArgumentNullException(nameof(arg));

So I've come up with the following set up:

public static class ArgumentValidator
{
    public interface IArgument<T>
    {
        string ParamName { get; }
        T Value { get; }
    }

    private class Argument<T>: IArgument<T>
    {
        public Argument(T argument, string paramName)
        {
            ParamName = paramName;
            Value = argument;
        }

        public string ParamName { get; }
        public T Value { get; }
    }

    public static IArgument<T> Validate<T>(this T argument, string paramName = null)
    {
        return new Argument<T>(argument, paramName ?? string.Empty);
    }

    public static IArgument<T> IsNotNull<T>(this IArgument<T> o)
    {
        if (ReferenceEquals(o.Value, null))
            throw new ArgumentNullException(o.ParamName);

        return o;
    }

    public static IArgument<T> IsSmallerThan<T, Q>(this IArgument<T> o, Q upperBound) where T : IComparable<Q> { ... }

    //etc.
}

And I can use it in the following way:

public Bar Foo(object flob)
{
     flob.Validate(nameof(flob)).IsNotNull().IsSmallerThan(flob.MaxValue);
}

Ideally I'd love to get rid of nameof(flob) in the Validate call and ultimately get rid of Validate alltogether; the only purpose of Validate is to avoid having to pass nameof(...) on every check down the chain.

Is there a way to get the name flob inside the Validate() method?

InBetween
  • 32,319
  • 3
  • 50
  • 90

1 Answers1

5

Doing that with an extension method is not that easy. It is easier with a static method that takes an LINQ expression (derived from devdigital's answer here):

public static T Validate<T>(this Expression<Func<T>> argument)
{
    var lambda = (LambdaExpression)argument;

    MemberExpression memberExpression;
    if (lambda.Body is UnaryExpression)
    {
        var unaryExpression = (UnaryExpression)lambda.Body;
        memberExpression = (MemberExpression)unaryExpression.Operand;
    }
    else
    {
        memberExpression = (MemberExpression)lambda.Body;
    }

    string name = memberExpression.Member.Name;

    Delegate d = lambda.Compile();

    return (T)d.DynamicInvoke();
}

The name inside is the name of the property you put in the method:

MyMethods.Validate(() => o);

Since the Validate returns T, you can use that further on. This might not be as performing as you want it to be, but this is the only viable option.

It is possible to make this an extension method too, you have to create the expression yourself by hand:

Expression<Func<object>> f = () => o; // replace 'object' with your own type

f.Validate();
Community
  • 1
  • 1
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • Thanks, this is pretty interesting. Is doing something similar form an extension method even possible? I can live with `Validate` a being normal static method but I am curious as to why it being an extension method makes things harder. – InBetween Feb 09 '16 at 10:08
  • Well, your property has to be an expression then... That isn't really working in my opinion. – Patrick Hofman Feb 09 '16 at 10:09