|
// 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.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using System.Threading;
namespace System.Dynamic.Utils
{
internal static class ContractUtils
{
/// <summary>
/// Returns an exception object to be thrown when code is supposed to be unreachable.
/// </summary>
[ExcludeFromCodeCoverage(Justification = "Unreachable")]
public static Exception Unreachable
{
get
{
Debug.Fail("Unreachable");
return new UnreachableException();
}
}
/// <summary>
/// Requires the <paramref name="precondition"/> to be <c>true</c>.
/// </summary>
/// <param name="precondition">
/// The precondition to check for being <c>true</c>.
/// </param>
/// <param name="paramName">
/// The parameter name to use in the <see cref="ArgumentException.ParamName"/> property when an exception is thrown.
/// </param>
/// <exception cref="ArgumentException">
/// Thrown if <paramref name="precondition"/> is <c>false</c>.
/// </exception>
public static void Requires([DoesNotReturnIf(false)] bool precondition, string paramName)
{
Debug.Assert(!string.IsNullOrEmpty(paramName));
if (!precondition)
{
throw Error.InvalidArgumentValue(paramName);
}
}
/// <summary>
/// Requires the <paramref name="value"/> to be non-<c>null</c>.
/// </summary>
/// <param name="value">
/// The value to check for being non-<c>null</c>.
/// </param>
/// <param name="paramName">
/// The parameter name to use in the <see cref="ArgumentException.ParamName"/> property when an exception is thrown.
/// </param>
/// <param name="index">
/// The index of the argument being checked for <c>null</c>.
/// If an exception is thrown, this value is used in <see cref="ArgumentException.ParamName"/> if it's greater than or equal to 0.
/// </param>
/// <exception cref="ArgumentNullException">
/// Thrown if <paramref name="value"/> is <c>null</c>.
/// </exception>
public static void RequiresNotNull(object value, string paramName, int index)
{
Debug.Assert(!string.IsNullOrEmpty(paramName));
if (value == null)
{
throw new ArgumentNullException(GetParamName(paramName, index));
}
}
/// <summary>
/// Requires the <paramref name="collection"/> to be non-empty.
/// </summary>
/// <param name="collection">
/// The collection to check for being non-empty.
/// </param>
/// <param name="paramName">
/// The parameter name to use in the <see cref="ArgumentException.ParamName"/> property when an exception is thrown.
/// </param>
/// <exception cref="ArgumentException">
/// Thrown if the <paramref name="collection"/> is empty.
/// </exception>
public static void RequiresNotEmpty<T>(ICollection<T> collection, string paramName)
{
ArgumentNullException.ThrowIfNull(collection, paramName);
if (collection.Count == 0)
{
throw Error.NonEmptyCollectionRequired(paramName);
}
}
/// <summary>
/// Requires the <paramref name="array"/> and all its items to be non-<c>null</c>.
/// </summary>
/// <param name="array">
/// The array to check for being non-<c>null</c> and containing non-<c>null</c> items.
/// </param>
/// <param name="arrayName">
/// The parameter name to use in the <see cref="ArgumentException.ParamName"/> property when an exception is thrown.
/// </param>
/// <exception cref="ArgumentNullException">
/// Thrown if the <paramref name="array"/> or any of its items is <c>null</c>.
/// </exception>
public static void RequiresNotNullItems<T>(IList<T> array, string arrayName)
{
Debug.Assert(!string.IsNullOrEmpty(arrayName));
ArgumentNullException.ThrowIfNull(array, arrayName);
for (int i = 0, n = array.Count; i < n; i++)
{
if (array[i] == null)
{
throw new ArgumentNullException(GetParamName(arrayName, i));
}
}
}
[Conditional("DEBUG")]
public static void AssertLockHeld(object lockObject)
{
Debug.Assert(Monitor.IsEntered(lockObject), "Expected lock is not held.");
}
private static string GetParamName(string paramName, int index) => index >= 0 ? $"{paramName}[{index}]" : paramName;
/// <summary>
/// Requires the range [offset, offset + count] to be a subset of [0, array.Count].
/// </summary>
/// <exception cref="ArgumentNullException">Array is <c>null</c>.</exception>
/// <exception cref="ArgumentOutOfRangeException">Offset or count are out of range.</exception>
public static void RequiresArrayRange<T>(IList<T> array, int offset, int count, string offsetName, string countName)
{
Debug.Assert(!string.IsNullOrEmpty(offsetName));
Debug.Assert(!string.IsNullOrEmpty(countName));
Debug.Assert(array != null);
ArgumentOutOfRangeException.ThrowIfNegative(count, countName);
ArgumentOutOfRangeException.ThrowIfNegative(offset, offsetName);
ArgumentOutOfRangeException.ThrowIfLessThan(array.Count - offset, count, offsetName);
}
}
}
|