Background and motivation
As #69590 added new throw helpers for ArgumentOutOfRangeException, I've started playing around with them trying to move an existing codebase to these new APIs, and one thing that quickly became apparent was how the "equal/not equal" case was currently missing. This proposal is about adding such APIs as well, so that these scenarios can also be supported.
API Proposal
namespace System;
public class ArgumentOutOfRangeException
{
public static void ThrowIfEqual<T>(T value, T other, [CallerArgumentExpression("value")] string? paramName = null) where T : IEquatable<T>;
public static void ThrowIfNotEqual<T>(T value, T other, [CallerArgumentExpression("value")] string? paramName = null) where T : IEquatable<T>;
}
I've tried to mirror the design of existing APIs such as ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual, which also take a non-nullable generic, constrained to an interface (in that case it's IComparable<T>).
API Usage
Eg. in ComputeSharp I have a bunch of methods to copy to/from MD textures. Consider this one, using this API:
public static void CopyTo<T>(this Texture2D<T> source, T[,] destination)
where T : unmanaged
{
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(destination);
ArgumentOutOfRangeException.ThrowIfNotEqual(destination.GetLength(0), source.Height, nameof(destination));
ArgumentOutOfRangeException.ThrowIfNotEqual(destination.GetLength(1), source.Width, nameof(destination));
source.CopyTo(ref destination[0, 0], destination.Length, 0, 0, source.Width, source.Height);
}
In general this would be useful whenever people need to explicitly check against a single value (same as eg. ThrowIfZero).
Open questions
The IComparable<T> constraint means Enum values can't use this API. Should we not use the constraint and instead just have the API call EqualityComparer<T>.Default.Equals instead? Are there performance considerations in that case?
Background and motivation
As #69590 added new throw helpers for
ArgumentOutOfRangeException, I've started playing around with them trying to move an existing codebase to these new APIs, and one thing that quickly became apparent was how the "equal/not equal" case was currently missing. This proposal is about adding such APIs as well, so that these scenarios can also be supported.API Proposal
I've tried to mirror the design of existing APIs such as
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual, which also take a non-nullable generic, constrained to an interface (in that case it'sIComparable<T>).API Usage
Eg. in ComputeSharp I have a bunch of methods to copy to/from MD textures. Consider this one, using this API:
In general this would be useful whenever people need to explicitly check against a single value (same as eg.
ThrowIfZero).Open questions
The
IComparable<T>constraint meansEnumvalues can't use this API. Should we not use the constraint and instead just have the API callEqualityComparer<T>.Default.Equalsinstead? Are there performance considerations in that case?