C# 9.0 から導入された「最上位レベルステートメント(Top-level statements)」を使用すると、従来のエントリーポイント(Main メソッド)を明示的に記述する必要がなくなります。これにより、スクリプト言語のようにシンプルにプログラムを開始でき、特に小規模なツールや学習用途においてボイラープレートコード(定型コード)を大幅に削減できます。
本記事では、従来の書き方と比較しながら、最上位レベルステートメントの具体的な使い方と仕様について解説します。
従来の記述方法との比較
アプリケーションが起動した際に、現在時刻を表示する単純なプログラムを例に比較します。
従来の書き方(C# 8.0 以前)
従来は、プログラムのエントリーポイントとして class Program と static void Main を定義する必要がありました。ネストが深くなり、数行の処理を行うだけでも多くの記述が必要です。
using System;
namespace TimeDisplayApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"現在の時刻: {DateTime.Now}");
}
}
}
最上位レベルステートメント(C# 9.0 以降)
最上位レベルステートメントを使用すると、namespace、class、Main メソッドの定義をすべて省略できます。ファイルの上から順に実行したい処理を書くだけです。
using System;
// Mainメソッドやクラス定義は不要
Console.WriteLine($"現在の時刻: {DateTime.Now}");
// 戻り値を返すことも可能(int型の終了コード)
return 0;
コンパイラが内部的に Main メソッドを生成するため、動作としては従来の方法と全く変わりません。
最上位レベルステートメントの機能と仕様
単に短く書けるだけでなく、エントリーポイントに必要な機能も暗黙的にサポートされています。
コマンドライン引数(args)の利用
Main(string[] args) を定義していなくても、args という名前の変数が暗黙的に利用可能です。コマンドライン引数はこの変数に格納されます。
using System;
if (args.Length > 0)
{
foreach (var arg in args)
{
Console.WriteLine($"引数: {arg}");
}
}
else
{
Console.WriteLine("引数が指定されていません。");
}
メソッドの定義と呼び出し
最上位レベルステートメントのファイル内であれば、ローカル関数のようにお手軽にメソッドを定義して呼び出すことができます。これらのメソッドは最上位のステートメントの後に記述します。
using System;
var message = "システムチェックを開始します。";
Log(message);
// 処理の実行
await Task.Delay(1000); // 非同期処理もそのまま書ける
Log("完了しました。");
// ファイル下部にメソッドを定義
void Log(string text)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {text}");
}
注意点と制約
最上位レベルステートメントを使用する際は、いくつかのルールを守る必要があります。
- プロジェクト内で1つのファイルのみ 最上位レベルステートメントを含むファイルは、1つのプロジェクトにつき1つしか存在できません。コンパイラがエントリーポイントを生成するため、複数あると競合します。
- 記述順序のルール
usingディレクティブはファイルの先頭に記述し、その後に最上位レベルステートメント(実行コード)を記述します。クラスや名前空間の定義は、すべての最上位レベルステートメントの後に記述する必要があります。
using System;
// 1. 実行コード(最上位レベルステートメント)
Console.WriteLine("Hello");
// 2. クラス定義(必ず実行コードの後に書く)
public class MyHelper
{
public void DoSomething() { }
}
まとめ
最上位レベルステートメントを利用することで、C# プログラムの記述量を減らし、本質的なロジックに集中しやすくなります。
class ProgramやMainメソッドの定型文を省略可能。args変数でコマンドライン引数にアクセス可能。awaitを使用して非同期処理も直感的に記述可能。
特にコンソールアプリケーションの作成や、機能のプロトタイピングにおいて非常に有用な機能です。プロジェクトの性質に合わせて積極的に活用してください。
