次の方法で共有


Guard クラス

Guard クラスを使用して、効率的な方法でメソッド引数を検証します。 このクラスは、手動でチェックを記述して例外をスローするよりも、より高速で、冗長性が低く、表現力が高く、エラーが起こりにくくなります。

プラットフォーム API:GuardCallerArgumentExpressionAttribute

しくみ

Guard API は、次の 3 つの主要な原則を念頭に置いて構築されています。

  • 高速であること。 これを実現するために、すべての API は、呼び出し元で可能な限り少ないコードを生成するように設計されており、各単一の Guard API は (ほぼ常に) インライン化されます。 さらに、一般的な型 (プリミティブ数値型など) を操作するときに可能な最も効率的なアセンブリ コードを実現するために、T4 テンプレートを使用して特殊なメソッドが生成されます。
  • わかりやすいこと。 各 Guard API は、問題の原因を明確に示す詳細な例外メッセージを生成し、必要に応じて追加情報 (現在の変数値など) を指定します。
  • 直感的であること。 これを実現するために、すべての Guard API には、各 API が何を行う必要があるかをすぐに明確にする、わかりやすい名前が付けられます。 これにより、チェックを記述する負担が開発者から離れ、自然言語を使用して条件を表現できるようになります。

構文

次のコード スニペットは、いくつかのチェックが明示的に行われ、手動で throw ステートメントが実行されているサンプル メソッドを示しています。

public static void SampleMethod(int[] array, int index, Span<int> span, string text)
{
    if (array is null)
    {
        throw new ArgumentNullException(nameof(array), "The array must not be null");
    }

    if (array.Length >= 10)
    {
        throw new ArgumentException($"The array must have less than 10 items, had a size of {array.Length}", nameof(array));
    }

    if (index < 0 || index >= array.Length)
    {
        throw new ArgumentOutOfRangeException(nameof(index), $"The index must be in the [0, {array.Length}) range, was {index}");
    }

    if (span.Length < array.Length)
    {
        throw new ArgumentException($"The target span is shorter than the input array, had a length of {span.Length}", nameof(span));
    }

    if (string.IsNullOrEmpty(text))
    {
        throw new ArgumentException("The input text can't be null or empty", nameof(text));
    }
}

同じ方法を次に示しますが、 Guard API を使用して入力引数を検証します。

public static void SampleMethod(int[] array, int index, Span<int> span, string text)
{
    Guard.IsNotNull(array);
    Guard.HasSizeGreaterThanOrEqualTo(array, 10);
    Guard.IsInRangeFor(index, array);
    Guard.HasSizeLessThanOrEqualTo(array, span);
    Guard.IsNotNullOrEmpty(text);
}

Guard API は、可能な限り最速の方法で必要なチェックを実行し、失敗した場合は適切な形式のメッセージで適切な例外をスローします。

手記

Guard API は、検証対象の引数の名前を自動的に推論するために、[CallerArgumentExpression] に依存します。 そのためには、プロジェクトで C# 10 を有効にする必要があります。 言語の下位バージョンを使用している場合は、パラメーター名を手動で渡す必要があります。たとえば、 nameof() を使用して参照する必要があります (たとえば、 Guard.IsNotNull(array, nameof(array))))。

メソッド

Guard クラスには、多数の異なる API とオーバーロードがあります。 次の表では、その一部について説明します。

全般

メソッド 戻り値の型 説明
IsNotNull<T>(T, string) 無効 入力値が null ではないことをアサートします
IsOfType<T>(object, string) 無効 入力値が特定の型であることをアサートします
IsAssignableToType<T>(object, string) 無効 指定した型に入力値を割り当てることができることをアサートします
IsReferenceEqualTo<T>(T, T, string) 無効 入力値がターゲット値と同じインスタンスである必要があることをアサートします
IsTrue(bool, string) 無効 入力値が true である必要があることをアサートします

比較

メソッド 戻り値の型 説明
IsEqualTo<T>(T, T, string) 無効 入力値が指定した値と等しい必要があることをアサートします
IsBitwiseEqualTo<T>(T, T, string) 無効 入力値が、指定した値とビットごとの一致である必要があることをアサートします
IsLessThan<T>(T, T, string) 無効 入力値が指定した値より小さい必要があることをアサートします
IsLessThanOrEqualTo<T>(T, T, string) 無効 入力値が指定した値以下である必要があることをアサートします
IsInRange<T>(T, T, T, string) 無効 入力値が [最小、最大) の範囲である必要があることをアサートします
IsBetween<T>(T, T, T, string name) 無効 入力値が (最小、最大) 間隔である必要があることをアサートします
IsBetweenOrEqualTo<T>(T, T, T, string name) 無効 入力値が [最小、最大] 間隔である必要があることをアサートします

ストリングス

メソッド 戻り値の型 説明
IsNotNullOrEmpty(string, string) 無効 入力文字列インスタンスが null または空でないことをアサートします
IsNotNullOrWhiteSpace(string, string) 無効 入力文字列インスタンスが null または空白でないことをアサートします。

コレクション

メソッド 戻り値の型 説明
IsNotEmpty<T>(T[], string) 無効 入力配列インスタンスが空でないことをアサートします
HasSizeEqualTo<T>(T[], int, string) 無効 入力配列インスタンスに指定した値のサイズが必要であることをアサートします
HasSizeAtLeast<T>(T[], int, string) 無効 入力配列のサイズが、指定した値以上である必要があることをアサートします。
IsInRangeFor<T>(int, T[], string) 無効 入力インデックスが特定の配列に対して有効であることをアサートします
HasSizeLessThanOrEqualTo<T>(T[], T[], string) 無効 ソース配列のサイズがコピー先配列のサイズ以下である必要があることをアサートします

用事

メソッド 戻り値の型 説明
IsCompleted(Task, string) 無効 入力タスクが完了状態であることをアサートします
IsNotCanceled(Task, string) 無効 入力タスクが取り消されないことをアサートします

使用例

その他の例については、単体テストを参照してください。