Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check for null parameters using an attribute

Tags:

c#

Is it possible to check the value of a parameter natively using an attribute? I have seen some system attributes like [FromUri] used this way. I'm hoping for something like this:

public void Method([NotNull] string name, [NotNull] DateTime? date)
{  }

where NotNull is an attribute that checks the value to see if it is null. If the value is null it will throw an error.

Here is what I currently have

I'm currently using a static helper class that takes an expression and the parameter itself to determine whether the value is null and uses the expression to determine the name of the parameter.

// Invoke method within ArgumentHelper class
ArgumentHelper.RequireNotNullOrEmpty(() => state, state);

// Method within static class ArgumentHelper
public static void RequireNotNullOrEmpty<T>(this Expression<Func<T>> argumentExpression, string value)
    {
        var body = ((MemberExpression)argumentExpression.Body);
        if (string.IsNullOrEmpty(value))
        {
            // Throw error "Required field '" + body.Member.Name + "' is missing.";
        }
    }

Bonus: It would also be nice if I could somehow get the name of the variable without passing a string with its name, just like my current solution.

like image 482
Brad Germain Avatar asked Apr 10 '14 13:04

Brad Germain


2 Answers

Definitely not the most performant, but you're on the right track. Here's a wrapper that does a little of what PostSharp would be doing in IL. This is only good for passing objects, it breaks down as is when passing another method as a parameter. However, fixing that problem is just a little more work.

In production I would expand this to build the reflection into a delegate that I could cache for later use.

public class SomeClass
{
    public void Method([NotNull] string Param1, [NotNull] string Param2)
    { }
}

public static class SomeClassExtensions
{
    public static void InvokeWithNullCheck<TObject>(this TObject obj, Expression<Action<TObject>> expression)
    {
        var body = (MethodCallExpression)expression.Body;

        foreach(var parameter in body.Method.GetParameters())
        {
            bool hasNotNullAttribute = parameter.CustomAttributes.Any(x => x.AttributeType.Equals(typeof(NotNullAttribute)));
            if(hasNotNullAttribute && ((ConstantExpression)body.Arguments[parameter.Position]).Value == null)
            {
                throw new ArgumentException(String.Format("Mandatory parameter {0} was not supplied.", parameter.Name));
            }
        }

        expression.Compile()(obj);
    }
}

[TestFixture]
public class SomeClassTests
{
    [Test]
    public void Test()
    {
        var test = new SomeClass();
        Assert.Throws<ArgumentException>(() => test.InvokeWithNullCheck(x => x.Method(null, "Test")));
    }
}
like image 170
Nishmaster Avatar answered Sep 21 '22 05:09

Nishmaster


Take a look at PostSharp (see: http://www.postsharp.net). It provides a lot of attributes like that one you are looking for.

PostSharp is a precompiler which will lookup the attributes in your code and generate appropriate code like parameter validation.

like image 32
Martin Mulder Avatar answered Sep 19 '22 05:09

Martin Mulder