-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Background
It's quite verbose to validate arguments because you have to write an if-statement and throw new XXXException for each validation. Even with C# 7's new throw-expressions, you still have to write out the latter part. This makes people write their own helper classes for validating arguments, e.g. here or here. It would be nice if we had such a helper class as part of the framework.
Proposal
namespace System
{
public static class Verify
{
public static void Argument(bool condition, string message, string argumentName);
public static void InRange(bool condition, string argumentName);
public static void InRange(string s, int index, int count, string sName, string indexName, string countName);
public static void InRange<T>(T[] array, int index, int count, string arrayName, string indexName, string countName);
public static void NotEmpty<T>(IEnumerable<T> source, string sourceName);
public static void NotNegative(int argument, string argumentName);
public static void NotNull(bool condition, string argumentName);
public static void NotNull<T>(T argument, string argumentName) where T : class;
public static void Positive(int argument, string argumentName);
}
}
// Sample usage:
T MyGenericMethod<T>(T[] array, int index, int count)
{
// Note: All of this is equivalent to Verify.InRange(array, index, count, nameof(array), nameof(index), nameof(count)).
// The arguments are validated manually for demo purposes.
Verify.NotNull(array, nameof(array));
Verify.NotNegative(index, nameof(index));
Verify.NotNegative(count, nameof(count));
Verify.InRange(array.Length - index >= count, nameof(index));
}A sample implementation can be found here.
Remarks
-
In my experience, it's common to validate things like a signed integer being positive/nonnegative, so those patterns will get their own
Positive/NotNegativemethods. This will enable us to provide a better error message if such a check fails. These methods throw the same exception type asInRange.- Same applies for
InRange,NotEmpty
- Same applies for
-
The class will work nicely with
using static:
using static System.Verify;
T MyGenericMethod<T>(T[] array, int index, int count)
{
NotNull(array, nameof(array));
NotNegative(index, nameof(index));
NotNegative(count, nameof(count));
InRange(array.Length - index >= count, nameof(index));
}- The extra
NotNulloverload taking aboolcovers the rare cases when people are writing generic code, and the parameter might be null but the compiler can't guarantee that it's a class. e.g. Like here. It also covers the rare times when someone would want to verify a nullable is non-null.- I didn't include a
NotNull<T>(T?, string) where T : structnullable overload since if someone thinks a nullable is non-null they would likely 1) not accept a nullable parameter in the first place, or 2) if they're calling some method they know returns a non-null nullable, they're likely to cast theT?to aTor call.Value, which do the validation automatically, instead of bothering to validate themselves.
- I didn't include a
This is a follow-up to https://github.com/dotnet/corefx/issues/12509 after putting some thought into the API.