// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.Serialization; namespace System { /// <summary> /// The exception that is thrown when the value of an argument is outside the allowable range of values as defined by the invoked method. /// </summary> [Serializable] [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public class ArgumentOutOfRangeException : ArgumentException { private readonly object? _actualValue; // Creates a new ArgumentOutOfRangeException with its message // string set to a default message explaining an argument was out of range. public ArgumentOutOfRangeException() : base(SR.Arg_ArgumentOutOfRangeException) { HResult = HResults.COR_E_ARGUMENTOUTOFRANGE; } public ArgumentOutOfRangeException(string? paramName) : base(SR.Arg_ArgumentOutOfRangeException, paramName) { HResult = HResults.COR_E_ARGUMENTOUTOFRANGE; } public ArgumentOutOfRangeException(string? paramName, string? message) : base(message ?? SR.Arg_ArgumentOutOfRangeException, paramName) { HResult = HResults.COR_E_ARGUMENTOUTOFRANGE; } public ArgumentOutOfRangeException(string? message, Exception? innerException) : base(message ?? SR.Arg_ArgumentOutOfRangeException, innerException) { HResult = HResults.COR_E_ARGUMENTOUTOFRANGE; } public ArgumentOutOfRangeException(string? paramName, object? actualValue, string? message) : base(message ?? SR.Arg_ArgumentOutOfRangeException, paramName) { _actualValue = actualValue; HResult = HResults.COR_E_ARGUMENTOUTOFRANGE; } [Obsolete(Obsoletions.LegacyFormatterImplMessage, DiagnosticId = Obsoletions.LegacyFormatterImplDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] [EditorBrowsable(EditorBrowsableState.Never)] protected ArgumentOutOfRangeException(SerializationInfo info, StreamingContext context) : base(info, context) { _actualValue = info.GetValue("ActualValue", typeof(object)); } [Obsolete(Obsoletions.LegacyFormatterImplMessage, DiagnosticId = Obsoletions.LegacyFormatterImplDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] [EditorBrowsable(EditorBrowsableState.Never)] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("ActualValue", _actualValue, typeof(object)); } public override string Message { get { string s = base.Message; if (_actualValue != null) { string valueMessage = SR.Format(SR.ArgumentOutOfRange_ActualValue, _actualValue); if (s == null) return valueMessage; return s + Environment.NewLineConst + valueMessage; } return s; } } // Gets the value of the argument that caused the exception. public virtual object? ActualValue => _actualValue; [DoesNotReturn] private static void ThrowZero<T>(T value, string? paramName) => throw new ArgumentOutOfRangeException(paramName, value, SR.Format(SR.ArgumentOutOfRange_Generic_MustBeNonZero, paramName, value)); [DoesNotReturn] private static void ThrowNegative<T>(T value, string? paramName) => throw new ArgumentOutOfRangeException(paramName, value, SR.Format(SR.ArgumentOutOfRange_Generic_MustBeNonNegative, paramName, value)); [DoesNotReturn] private static void ThrowNegativeOrZero<T>(T value, string? paramName) => throw new ArgumentOutOfRangeException(paramName, value, SR.Format(SR.ArgumentOutOfRange_Generic_MustBeNonNegativeNonZero, paramName, value)); [DoesNotReturn] private static void ThrowGreater<T>(T value, T other, string? paramName) => throw new ArgumentOutOfRangeException(paramName, value, SR.Format(SR.ArgumentOutOfRange_Generic_MustBeLessOrEqual, paramName, value, other)); [DoesNotReturn] private static void ThrowGreaterEqual<T>(T value, T other, string? paramName) => throw new ArgumentOutOfRangeException(paramName, value, SR.Format(SR.ArgumentOutOfRange_Generic_MustBeLess, paramName, value, other)); [DoesNotReturn] private static void ThrowLess<T>(T value, T other, string? paramName) => throw new ArgumentOutOfRangeException(paramName, value, SR.Format(SR.ArgumentOutOfRange_Generic_MustBeGreaterOrEqual, paramName, value, other)); [DoesNotReturn] private static void ThrowLessEqual<T>(T value, T other, string? paramName) => throw new ArgumentOutOfRangeException(paramName, value, SR.Format(SR.ArgumentOutOfRange_Generic_MustBeGreater, paramName, value, other)); [DoesNotReturn] private static void ThrowEqual<T>(T value, T other, string? paramName) => throw new ArgumentOutOfRangeException(paramName, value, SR.Format(SR.ArgumentOutOfRange_Generic_MustBeNotEqual, paramName, (object?)value ?? "null", (object?)other ?? "null")); [DoesNotReturn] private static void ThrowNotEqual<T>(T value, T other, string? paramName) => throw new ArgumentOutOfRangeException(paramName, value, SR.Format(SR.ArgumentOutOfRange_Generic_MustBeEqual, paramName, (object?)value ?? "null", (object?)other ?? "null")); /// <summary>Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is zero.</summary> /// <param name="value">The argument to validate as non-zero.</param> /// <param name="paramName">The name of the parameter with which <paramref name="value"/> corresponds.</param> public static void ThrowIfZero<T>(T value, [CallerArgumentExpression(nameof(value))] string? paramName = null) where T : INumberBase<T> { if (T.IsZero(value)) ThrowZero(value, paramName); } /// <summary>Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is negative.</summary> /// <param name="value">The argument to validate as non-negative.</param> /// <param name="paramName">The name of the parameter with which <paramref name="value"/> corresponds.</param> public static void ThrowIfNegative<T>(T value, [CallerArgumentExpression(nameof(value))] string? paramName = null) where T : INumberBase<T> { if (T.IsNegative(value)) ThrowNegative(value, paramName); } /// <summary>Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is negative or zero.</summary> /// <param name="value">The argument to validate as non-zero or non-negative.</param> /// <param name="paramName">The name of the parameter with which <paramref name="value"/> corresponds.</param> public static void ThrowIfNegativeOrZero<T>(T value, [CallerArgumentExpression(nameof(value))] string? paramName = null) where T : INumberBase<T> { if (T.IsNegative(value) || T.IsZero(value)) ThrowNegativeOrZero(value, paramName); } /// <summary>Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is equal to <paramref name="other"/>.</summary> /// <param name="value">The argument to validate as not equal to <paramref name="other"/>.</param> /// <param name="other">The value to compare with <paramref name="value"/>.</param> /// <param name="paramName">The name of the parameter with which <paramref name="value"/> corresponds.</param> public static void ThrowIfEqual<T>(T value, T other, [CallerArgumentExpression(nameof(value))] string? paramName = null) { if (EqualityComparer<T>.Default.Equals(value, other)) ThrowEqual(value, other, paramName); } /// <summary>Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is not equal to <paramref name="other"/>.</summary> /// <param name="value">The argument to validate as equal to <paramref name="other"/>.</param> /// <param name="other">The value to compare with <paramref name="value"/>.</param> /// <param name="paramName">The name of the parameter with which <paramref name="value"/> corresponds.</param> public static void ThrowIfNotEqual<T>(T value, T other, [CallerArgumentExpression(nameof(value))] string? paramName = null) { if (!EqualityComparer<T>.Default.Equals(value, other)) ThrowNotEqual(value, other, paramName); } /// <summary>Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is greater than <paramref name="other"/>.</summary> /// <param name="value">The argument to validate as less or equal than <paramref name="other"/>.</param> /// <param name="other">The value to compare with <paramref name="value"/>.</param> /// <param name="paramName">The name of the parameter with which <paramref name="value"/> corresponds.</param> public static void ThrowIfGreaterThan<T>(T value, T other, [CallerArgumentExpression(nameof(value))] string? paramName = null) where T : IComparable<T> { if (value.CompareTo(other) > 0) ThrowGreater(value, other, paramName); } /// <summary>Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is greater than or equal <paramref name="other"/>.</summary> /// <param name="value">The argument to validate as less than <paramref name="other"/>.</param> /// <param name="other">The value to compare with <paramref name="value"/>.</param> /// <param name="paramName">The name of the parameter with which <paramref name="value"/> corresponds.</param> public static void ThrowIfGreaterThanOrEqual<T>(T value, T other, [CallerArgumentExpression(nameof(value))] string? paramName = null) where T : IComparable<T> { if (value.CompareTo(other) >= 0) ThrowGreaterEqual(value, other, paramName); } /// <summary>Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is less than <paramref name="other"/>.</summary> /// <param name="value">The argument to validate as greater than or equal than <paramref name="other"/>.</param> /// <param name="other">The value to compare with <paramref name="value"/>.</param> /// <param name="paramName">The name of the parameter with which <paramref name="value"/> corresponds.</param> public static void ThrowIfLessThan<T>(T value, T other, [CallerArgumentExpression(nameof(value))] string? paramName = null) where T : IComparable<T> { if (value.CompareTo(other) < 0) ThrowLess(value, other, paramName); } /// <summary>Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is less than or equal <paramref name="other"/>.</summary> /// <param name="value">The argument to validate as greater than than <paramref name="other"/>.</param> /// <param name="other">The value to compare with <paramref name="value"/>.</param> /// <param name="paramName">The name of the parameter with which <paramref name="value"/> corresponds.</param> public static void ThrowIfLessThanOrEqual<T>(T value, T other, [CallerArgumentExpression(nameof(value))] string? paramName = null) where T : IComparable<T> { if (value.CompareTo(other) <= 0) ThrowLessEqual(value, other, paramName); } } }