-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Background and motivation
The ThrowIfEqual and ThrowIfNotEqual methods on the ArgumentOutOfRangeException class both have a where T : IEquatable<T>? constraint. However, the implementations of these methods do not seem to rely on this constraint, using EqualityComparer<T>.Default.Equals(T?, T?), which does not require T to implement IEquatable<T>.
The IEquatable<T> constraint prevents us from using the ThrowIfEqual and ThrowIfNotEqual methods on nullable value types (e.g., int?).
However, we can circumvent this constraint by wrapping the parameters in a ValueTuple<T> struct because ValueTuple<T> implements IEquatable<ValueTuple<T>>, but does not require T : IEquatable<T>. For example:
int? x = 10;
ArgumentOutOfRangeException.ThrowIfNotEqual(new ValueTuple<int?>(x), new ValueTuple<int?>(20));Therefore it seems that the IEquatable<T> constraint should be removed from the ThrowIfEqual and ThrowIfNotEqual methods given that the ThrowIfEqual method is basically performing the same function as ValueTuple<T>.Equals(ValueTuple<T>), which does not have this constraint.
API Proposal
namespace System;
public class ArgumentOutOfRangeException : ArgumentException
{
public static void ThrowIfEqual<T>(T value, T other,
[CallerArgumentExpression(nameof(value))] string? paramName = null);
public static void ThrowIfNotEqual<T>(T value, T other,
[CallerArgumentExpression(nameof(value))] string? paramName = null);
}API Usage
int? x = 10;
ArgumentOutOfRangeException.ThrowIfNotEqual(x, 20);Alternative Designs
No response
Risks
No response