9

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.

9
  • 1
    Your static helper class seems to be a lot more expensive to process compared to a simple == null Commented Apr 10, 2014 at 13:45
  • Is it possible to check the value of a parameter natively using an attribute? That's not really what attributes are for. Attributes are for decorating classes, methods, properties and arguments with meta data, not for actually doing processing itself. You'd still need either the caller or your function to actually check for null, in which case it would be easier to just check for null. You won't get automatic run-time checking. Commented Apr 10, 2014 at 13:52
  • 1
    The [FromUri] property only works the way it does because the caller (which is the web api itself) checks the attributes of the method it's trying to call and if it sees that attribute, it knows to insert the value from the uri. The attribute itself doesn't do that. It's the callers responsibility. Commented Apr 10, 2014 at 13:54
  • @MattBurland thanks for the response. You mentioned the attributes being used more for metadata and not processing. I know for the properties I have a [Required] tag that makes sure the property is not null and if it is it throws an error. Isn't this similar to what I'm looking for, or am I misunderstanding what it is actually doing? BTW I'm not trying to be conflicting, I'm just truly trying to understand this stuff. I'm still learning. :) Commented Apr 10, 2014 at 14:08
  • @BradGermain: Yes and no. The [Required] tag doesn't do anything at all unless the code using those properties actually checks it. It used for validation where the validation code will run through all the properties in your model and check to see if they have the [Required] attribute and if they do, it checks for null. It's still the responsibility of the calling code to actually check. By itself, it does nothing. Commented Apr 10, 2014 at 14:18

2 Answers 2

3

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")));
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Can you explain(or provide a link) how to “build the reflection into a delegate”?
2

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.

3 Comments

Thanks for posting @MartinMulder. I have heard of PostSharp as being a possible solution, but I was wondering if there was anyway of doing it natively without installing any additional software. I'm limited to what is installed by default in visual studio 2013.
So... Enterprise Library is not an option?
Is PostSharp a part of the Enterprise Library? If so, what version was it introduced, because we have Enterprise Library 4.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.