1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

.NET 9からDebug.Assertが、アサーションの条件をデフォルトで表示してくれるようになった

Last updated at Posted at 2025-02-15

Debug.Asesrtはプログラム開発中にロジックのエラーを識別するために使われることが多いメソッドです。Debug.Asesrt(Boolean)の引数がfalseなら、メッセージを出力し呼び出しスタックを表示してくれます。デフォルトでは、Debug.Assertメソッドはデバッグビルドのみで機能します。

さて、このDebug.Assertメソッドを使ったこんなプログラムを用意します。

using System.Diagnostics;

public static class Program
{
    public static void Main(string[] args)
    {
        SayHello(" ");
    }
    
    static void SayHello(string name)
    {
        Debug.Assert(!string.IsNullOrWhiteSpace(name));
        Console.WriteLine($"Hello, {name}!");
    }
}

.NET 8まではこれを実行すると、次のように表示されました。アサーションに失敗したことと、そのアサーションのプログラムのパスと行数がわかるので、便利ですね。

Process terminated. Assertion failed.
   at Program.SayHello(String name) in 「ここにプログラムのパスと行数」
   at Program.Main(String[] args) in 「ここにプログラムのパスと行数」

.NET 9から、これがさらに便利になって、条件をデフォルトで表示してくれるようになりました。先ほどのプログラムを.NET 9で実行すると、「!string.IsNullOrWhiteSpace(name)」というアサーションの条件を追加して表示してくれます。

Process terminated. Assertion failed.
!string.IsNullOrWhiteSpace(name)
   at Program.SayHello(String name) in 「ここにプログラムのパスと行数」
   at Program.Main(String[] args) in 「ここにプログラムのパスと行数」

.NET 9より前でも、「Assert(Boolean, String)」を使えば、同じようなことができますが、多少面倒ですね。

static void SayHello(string name)
{
    Debug.Assert(!string.IsNullOrWhiteSpace(name), "!string.IsNullOrWhiteSpace(name)");
    Console.WriteLine($"Hello, {name}!");
}

デバッグビルドのIL(中間言語)を見て、どういう仕組みになっているか確認してみます。次のコードは、SayHelloメソッドのILです。

  .method private hidebysig static void
    SayHello(
      string name
    ) cil managed
  {
    .maxstack 8

    // [11 5 - 11 6]
    IL_0000: nop

    // [12 9 - 12 92]
    IL_0001: ldarg.0      // name
    IL_0002: call         bool [System.Runtime]System.String::IsNullOrWhiteSpace(string)
    IL_0007: ldc.i4.0
    IL_0008: ceq
    IL_000a: ldstr        "!string.IsNullOrWhiteSpace(name)"
    IL_000f: call         void [System.Runtime]System.Diagnostics.Debug::Assert(bool, string)
    IL_0014: nop

    // [13 9 - 13 46]
    IL_0015: ldstr        "Hello, "
    IL_001a: ldarg.0      // name
    IL_001b: ldstr        "!"
    IL_0020: call         string [System.Runtime]System.String::Concat(string, string, string)
    IL_0025: call         void [System.Console]System.Console::WriteLine(string)
    IL_002a: nop

    // [14 5 - 14 6]
    IL_002b: ret

  } // end of method Program::SayHello

「IL_000a: ldstr "!string.IsNullOrWhiteSpace(name)"」に注目してください。
.NET 9では、こんな感じでアサーションが失敗した場合に表示する文字列が、IL内に定義されています。そして、よくILを見てみるとDebug.Asesrt(Boolean)ではなくて、「Assert(Boolean, String)」が呼ばれています。

実は、「Debug.Asesrt(Boolean)」ではなく「Assert(Boolean, String)」が呼ばれているのです。

  1. Debug.Asesrt(Boolean)」には、.NET 9から追加された「OverloadResolutionPriority」が付与されている。これにより、オーバーロード解決の優先度が下がっている。コードはこちら
  2. Assert(Boolean, String)」の第二引数messageに、CallerArgumentExpressionAttributeを付与して、デフォルト引数としてnullを設定。コードはこちら

この2個を組み合わせた時、

Debug.Assert(!string.IsNullOrWhiteSpace(name));

という呼び出しをした時に、「Assert(Boolean, String)」が呼ばれ、「"!string.IsNullOrWhiteSpace(name)"」という文字列が第二引数に渡されます。

その結果、.NET 9からDebug.Assertがアサーションの条件をデフォルトで表示してくれるようになっています。

Debug.Asesrt、.NET 9で進化して、雑に使った時に親切になってナイスですね。

リンク集

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?