-
Notifications
You must be signed in to change notification settings - Fork 5.1k
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