Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A single file argument verification library

0.00/5 (No votes)
18 Dec 2011 1  
A single file argument verification library

I would like to present here a little argument verification library that does not require you to type any string for specifying the name of the parameter you are checking. This makes the library faster to use, not intrusive in the actual method code, and refactor friendly. As a bonus, you can use it by just embedding a single file. We can see below an example, just to get immediately to the point:

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NContracts
{
    public class Demo
    {
        
        /// Classical not null verification
//----------> LINE 14
        public void DoSomething(string arg1)
        {
            Contract.Expect(() => arg1).IsNotNull();
        }
        
        /// Asserting an argument greather than another
        public void DoSomething(int min,int max)
        {
            Contract.Expect(() => min)
                .IsLessThan(int.MaxValue)
                .Meet(a => a <= max);
        }
       
        /// Validate an integer argument in a certain range
        public void DoSomething(int arg1)
        {
            Contract.Expect(() => arg1).IsGreatherThan(0)
                                       .IsLessThan(100);
                ;
           
        }
       
        /// Validate an array in length and asserts first element should be zero
        
        public void DoSomething(int[] array)
        {
//--------- LINE46
            Contract.Expect(() => array).Meet(a => a.Length > 0 && a.First() == 0);
        }
       
    }
}

As we can see, there is no magic string at all. All the argument names are guessed, thanks to the metadata contained in the Linq Expression we use. For example, the method at line 14 if called with a null value will report:

Value cannot be null.
Parameter name: arg1 

The same happens to the more complex check we do at line 46, when we write:

C#
Contract.Expect(() => array).Meet(a => a.Length> 0 && a.First() == 0);       

We have a complex predicate do meet, described by a lambda, standing that the input array should have first element zero, and non zero length. Notice that the name of the parameter is array, but we need to use another name for the argument of the lambda (in this case, I used ‘a’), the library is smart enough to understand that ‘a’ actually refers to array, and the error message will report it correctly if the condition is not met. Just to clarify, the message in case of failure would be:

Precondition not verified:((array.First() == 0) AndAlso (ArrayLength(array) > 1))
Parameter name: array       

Well it is not supposed to be a message to an end real user, it is a programmer friendly message, but such validation errors are supposed to be reported to a developer (and end user should not see method validation errors at all, should he?)

Well, Meet is a cutting edge function we can use for complex validations. Out of the box, for simpler cases we have some functions too, as we can see on the IContract interface definition:

C#
public interface IContract<t>
    {
        IContract<t> Is<tt>();
        IContract<t> IsEqual<tt>(TT of) where TT : T,IEquatable<tt>;
        IContract<t> IsGreatherThan<tt>(TT of) where TT : T,IComparable;
        IContract<t> IsGreatherThanOrEqual<tt>(TT of) where TT :T, IComparable;
        IContract<t> IsLessThan<tt>(TT of) where TT : T,IComparable;
        IContract<t> IsLessThanOrEq<tt>(TT of) where TT : T,IComparable;
        IContract<t> IsNot<tt>();
        IContract<t> IsNotEqual<tt>(TT of) where TT : T,IEquatable<tt>;
        IContract<t> IsNotNull();
        IContract<t> IsNotTheSameOf(object of);
        IContract<t> IsNull();
        IContract<t> IsTheSameOf(object of);
        IContract<t> Meet(Expression<predicate<t>> predicate);
    } 

An interesting portion of the codebase proposed is the one renaming the parameter on the lambda expression, to achieve the reported message reflecting the correct offending parameter. It is not so easy because plain string replacement would not work: we can have a parameter named ‘a’, seen in any place in the expression string representation and a plain replacement would resolve in a big mess, furthermore Expressions are immutable. So I found help on StackOverflow, and a reply to this question solved the problem, let see the “Renamer” at work (Thanks to Phil):

C#
static class  PredicateRewriter
        {
            public static Expression<predicate<t>> 
		Rewrite<t>(Expression<predicate<t>> exp
		, string newParamName)
            {
                var param = Expression.Parameter(exp.Parameters[0].Type, newParamName);
                var newExpression = new PredicateRewriterVisitor(param).Visit(exp);

                return (Expression<predicate<t>>)newExpression;
            }

            private class PredicateRewriterVisitor : ExpressionVisitor
            {
                private readonly ParameterExpression _parameterExpression;

                public PredicateRewriterVisitor(ParameterExpression parameterExpression)
                {
                    _parameterExpression = parameterExpression;
                }

                protected override Expression VisitParameter(ParameterExpression node)
                {
                    return _parameterExpression;
                }
            }
        }

Basically, it is a reusable class that takes the new name of the parameter and returns a copy of the input expression with the (single) argument changed.

To improve the library or just use it, please follow/check out the project on Bitbucket. Suggestions and comments are always welcome.


License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here