As a conclusion to the series of articles which started with a discussion on the various ways one can perform simple validations on method parameters using PostSharp, I thought I’d share my final thoughts on the matter as well as what I’ll be ultimately using my in own environment.
My primary concern with the original solution has had to do with both the signature of the actual base validation method as well as how we should pass the parameters we’re validating to it. Specifically, I wanted to make sure that the solution wasn’t introducing an excessive amount of boxing into code, which was a valid concern given the weak nature of the validation method’s signature (i.e. the fact that the validation method accepts the parameter as a System.Object type).
What We Have So Far
First of all, the reason why this is even important is because of the potential widespread usage of the validation method — if this is how we’re checking if something is null or not, then in we can expect a very large presence of such a method in a typical non-trivial application.
The original abstract validation method had the following signature:
public abstract void Validate(object target, object value, string parameterName);
The second parameter (value) represents the value of the parameter we’re validating, and it is the focal point of the topic at hand.
Let’s then go over some quick points that concern the implications of using a validation method with such a signature:
- Because the parameter type for the parameter’s value is System.Object, and not a generic type parameter, parameters which are value types will need to be boxed before being able to be provided to the method.
- Furthermore, if the parameter we are validating is a generic type parameter, then if at run-time that generic type parameter is substituted for a value type, that too will need to be boxed.
- While emitting a box instruction while a value type (or generic type parameter substituted with a value type) is on the stack incurs the traditional performance penalty associated with boxing operations, doing the same with a reference type (perhaps originally a generic type parameter substituted with a reference type) on the stack is essentially a nop.
- Because we’re weaving in raw MSIL here, we’re responsible for supplying the boxing instructions; this won’t be taken care of for us since the compiler is out of the equation…so we need to cover all these different scenarios.
My Approach and Strategy
After some review, I’ve settled on an approach in regards to what the validation method signature should look like as well as the strategy involving how we get the parameter value we’re validating to the method.
First of all, an ideal solution would be to not depend on a weakly based validation method, but rather make use of a validation method that accepts generic type parameters. While this would be cool, it’s actually not the most simple of endeavors. The generic type parameter can be defined on different levels (e.g. type vs method), and how do we call the method if we have no generic type parameter (i.e. the parameter we’re validating is a standard, non-generic type in its original form)?
Those different scenarios require you to do different things, and although I was able to pass some, I lack the inside knowledge of the PostSharp SDK to be able to cover all of them.
In the grand scheme of things, however, the approach I ultimately ended up using has proved to be more than adequate for the job. Given the body of work I’ve been involved with and the types of entities requiring validation, I found that the benefits that would be gained from the ideal solution to be extremely negligible in substance; therefore, it is the most justifiable approach when my own time is weighed as a factor in the equation.
The signature for the validation method ended up staying the same as it was originally. The type I am using for the parameter value remains System.Object. My strategy in regards to how I’m invoking the method is the following:
- If the parameter being validated is explicitly a value type, then it (of course) gets boxed before being passed to the validation method.
- If the parameter happens to a generic type parameter, then we only box it if it contains no generic constraints which guarantee the type substituted at run-time to be a reference type (e.g. a specific reference type or the class keyword).
- Furthermore, (further down the inheritance chain) any validation attributes which perform types of validations that only make sense when being conducted on reference types (e.g. NotNull) have built-in compile-time validation to ensure we it’s not being applied to any explicit value types.
The vast majority of parameter validations occurring in my main body of work are done on generic type parameters. Many times (though not always) these type parameters are constrained to be reference types. In the end, boxing almost never occurs, therefore this is quite acceptable to me.
To implement this strategy, I simply added a property named RequiresBoxing to the EntityDescription type I talked about in a previous article, which I set during the initialization of the EntityDescription object like so:
_requiresBoxing = entityType.IsValueType || (entityType.IsGenericParameter && !entityType.GetGenericParameterConstraints().Any(c => c.IsClass));
If, in the future, I ever found myself having to perform (let’s say) numerical-type validations on (obviously) value types, I’d probably create a separate class of validation advices which were specific in the value type being validated.