patterncsharpMinor
Code that uses reflection to validate arguments
Viewed 0 times
validatereflectionargumentsusesthatcode
Problem
I wrote an answer to this question on the Software Engineering SE site and was hoping to get it critiqued. (I'm told that it's acceptable to do so).
Essentially, this code uses reflection to check to ensure that none of the parameters of a method are
The weakness of this code is that it assumes that it's never valid for a string to consist of whitespace or be empty and that none of the arguments can be
My concerns:
The code is as follows:
As an example of how this is supposed to be used, here's my unit test for this method (which obviously passes):
```
[TestMethod]
public void ArgumentValidatorTests()
{
// Should run without exception
RunTest("a",
Essentially, this code uses reflection to check to ensure that none of the parameters of a method are
null and none of the strings are empty or consist only of whitespace. If one of those conditions is violated, it raises an exception on behalf of the caller.The weakness of this code is that it assumes that it's never valid for a string to consist of whitespace or be empty and that none of the arguments can be
null.My concerns:
- Is this overly convoluted/difficult to understand?
- Obviously any time you use reflection that's going to entail a performance hit. For the particular system I'm considering using this in, performance isn't a major concern, but if I end up using it in future projects, how much of a performance hit can I expect?
- Overall, is it actually worth using? Is this a reasonable application of the Don't Repeat Yourself principle?
The code is as follows:
public class ArgumentValidator
{
public static void ValidateArguments(params object[] methodArguments)
{
for (int i = 0; i
/// Get for a specific parameter from the calling method
///
/// Index of the argument
/// for the parameter in question
private static ParameterInfo GetCallingMethodParameterInfo(int index)
{
StackTrace trace = new StackTrace();
// Get the method that called the original method
MethodBase info = trace.GetFrame(2).GetMethod();
// Get information on the parameter that is null so we can add its name to the exception
ParameterInfo param = info.GetParameters()[index];
return param;
}As an example of how this is supposed to be used, here's my unit test for this method (which obviously passes):
```
[TestMethod]
public void ArgumentValidatorTests()
{
// Should run without exception
RunTest("a",
Solution
Repetition & Performance
You can save some time and improve the performance by not getting the stack for each parameter separately. As a matter of fact you can jump right to the right frame. The
Indicates to compilers that a method call or attribute should be ignored unless a specified conditional compilation symbol is defined.
Example:
You can save some time and improve the performance by not getting the stack for each parameter separately. As a matter of fact you can jump right to the right frame. The
GetCallingMethodParameterInfo is completely redundant. You can have everything at once by using LINQ.- Get the stack trace by skipping the first frame (you don't need it).
- Get the calling method parameters.
Zipthe arguments with the parameters.
- Use a
foreachto loop over both the arguments and their corresponsing parameter info at the same time.
- Check the
stringfirst not thenullbecause thestringrequires special handling.
- It might be a good idea to use this only in debug mode so the
Conditionalattribute is really handy here.
Indicates to compilers that a method call or attribute should be ignored unless a specified conditional compilation symbol is defined.
Example:
[Conditional("DEBUG")]
public static void ValidateArguments(params object[] args)
{
var stackTrace = new StackTrace(skipFrames: 1);
var method = stackTrace.GetFrame(0).GetMethod();
var parameters = method.GetParameters();
var items = args.Zip(parameters, (arg, param) => new
{
Argument = arg,
Parameter = param
});
foreach (var item in items)
{
if (item.Parameter.ParameterType == typeof(string))
{
var value = (string)item.Argument;
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException(
paramName: item.Parameter.Name,
message: $"{method.Name}'s argument \"{item.Parameter.Name}\" must not be null or white-space.");
}
}
if (item.Argument == null)
{
throw new ArgumentNullException(
paramName: item.Parameter.Name,
message: $"{method.Name}'s argument \"{item.Parameter.Name}\" must not be null");
}
}
}Code Snippets
[Conditional("DEBUG")]
public static void ValidateArguments(params object[] args)
{
var stackTrace = new StackTrace(skipFrames: 1);
var method = stackTrace.GetFrame(0).GetMethod();
var parameters = method.GetParameters();
var items = args.Zip(parameters, (arg, param) => new
{
Argument = arg,
Parameter = param
});
foreach (var item in items)
{
if (item.Parameter.ParameterType == typeof(string))
{
var value = (string)item.Argument;
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException(
paramName: item.Parameter.Name,
message: $"{method.Name}'s argument \"{item.Parameter.Name}\" must not be null or white-space.");
}
}
if (item.Argument == null)
{
throw new ArgumentNullException(
paramName: item.Parameter.Name,
message: $"{method.Name}'s argument \"{item.Parameter.Name}\" must not be null");
}
}
}Context
StackExchange Code Review Q#147476, answer score: 5
Revisions (0)
No revisions yet.