C#は長年、オブジェクト指向プログラミング言語として厳格な構造を求めてきました。
しかし、C# 9.0で導入されたトップレベルステートメントにより、その常識は大きく変わりました。
これまで必須だったclass Programやstatic void Mainといった「お決まりのコード(ボイラープレート)」を記述せずに、いきなり実行したい処理を書き始めることが可能になったのです。
本記事では、この革新的な機能の使い方から内部の仕組み、注意点までを詳しく解説します。
C# 9で導入されたトップレベルステートメントとは
トップレベルステートメントは、コンソールアプリケーションなどのプログラムの開始点(エントリポイント)を、クラスやメソッドの定義なしで記述できる機能です。
これにより、初心者にとっての学習障壁が下がるだけでなく、スクリプト作成やプロトタイピングの効率が飛躍的に向上しました。

従来の記述とトップレベルステートメントの比較
まずは、従来の方法とトップレベルステートメントを用いた方法で、どれほどコード量が変わるのかを確認してみましょう。
従来の記述方法 (C# 8.0 以前)
これまでは、たとえ一行のメッセージを表示するだけでも、以下のような構造が必要でした。
using System;
namespace HelloWorldApp
{
class Program
{
// プログラムの開始点となるMainメソッドが必須だった
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
トップレベルステートメントによる記述 (C# 9.0 以降)
同じ処理をトップレベルステートメントで記述すると、以下のようになります。
using System;
// クラスもメソッドも不要!いきなり実行コードを書ける
Console.WriteLine("Hello, World!");
わずか数行でプログラムが完結していることがわかります。
コードの意図が明確になり、本質的なロジックに集中できるようになりました。
なぜMainメソッドが省略できるのか
「省略できる」と言っても、実際にMainメソッドが消えてしまったわけではありません。
C#コンパイラがビルド時に、記述されたコードを自動的にMainメソッドの中へとラップしてくれるのです。

コンパイラは、トップレベルステートメントが含まれるファイルを見つけると、暗黙的にProgramというクラス名(実際には重複を避けるための特殊な名前)を作成し、そこにコードを配置します。
そのため、実行時には従来のC#プログラムと何ら変わらないパフォーマンスと動作が保証されます。
トップレベルステートメントの具体的な使い方
ここからは、より実践的な使い方を見ていきましょう。
単なる関数の呼び出しだけでなく、コマンドライン引数の利用や非同期処理もサポートされています。
コマンドライン引数 (args) の利用
従来のMainメソッドではstring[] argsという引数を通して外部からの入力を受け取っていました。
トップレベルステートメントでも、暗黙的な変数名「args」を使用することで、宣言なしで引数にアクセスできます。
using System;
// args変数は宣言しなくても最初から使える
if (args.Length > 0)
{
Console.WriteLine($"引数が指定されました: {args[0]}");
}
else
{
Console.WriteLine("引数はありません。");
}
実行結果の例 (引数あり)
引数が指定されました: HelloTopLevel
非同期処理 (await) の直接利用
現代のC#開発において不可欠な非同期処理も、トップレベルステートメントなら非常にスマートに記述できます。
awaitキーワードをそのまま使用でき、コンパイラは自動的にMainメソッドをasync Taskを返す形式として解釈します。
using System;
using System.Net.Http;
using System.Threading.Tasks;
// 非同期メソッドを直接 await できる
using var client = new HttpClient();
string content = await client.GetStringAsync("https://example.com");
Console.WriteLine($"データ取得完了。文字数: {content.Length}");
データ取得完了。文字数: 1256
このように、非同期プログラミングの導入コストが大幅に削減されているのが特徴です。
トップレベルステートメントの制限事項とルール
非常に便利な機能ですが、何でも自由に書けるわけではありません。
いくつかの重要な制約が存在します。
これらを理解していないと、コンパイルエラーに悩まされることになります。

1. プロジェクト内で1つのファイルのみ
トップレベルステートメントは、プロジェクト全体でたった1つのファイルにしか記述できません。
もし複数のファイルに記述してしまうと、コンパイラは「エントリポイントが複数存在する」と判断し、エラーを出力します。
| 項目 | ルール |
|---|---|
| 使用可能ファイル数 | プロジェクトにつき最大1ファイル |
| 主な用途 | Mainメソッドの代わりとなるメインファイル |
| 他のファイル | クラス定義やメソッド定義のみを記述する |
2. 記述の順序に厳格なルールがある
ファイル内での記述順序は、以下のように決められています。
この順序を乱すとエラーになります。
- Usingディレクティブ:最上部に記述します。
- トップレベルステートメント:実行したいコードを記述します。
- 型や名前空間の定義:クラスやインターフェースの定義は、実行コードの「後」に記述する必要があります。
using System; // 1. OK
Console.WriteLine("実行コード開始"); // 2. OK
var myObj = new MyClass();
myObj.SayHello();
// 3. 実行コードの後にクラス定義などを書くのはOK
class MyClass
{
public void SayHello() => Console.WriteLine("Hello from MyClass!");
}
もし、class MyClassの後にConsole.WriteLineを記述すると、コンパイラはそれをクラス内の記述と勘違いするか、文法エラーとして扱います。
3. 名前空間の扱いに注意
トップレベルステートメントを記述する際、そのコード自体をnamespaceブロックで囲むことはできません。
トップレベルに書かれたコードは、「グローバルな名前空間」に属するものとして扱われます。
どのような場面で使うべきか?
トップレベルステートメントは、すべてのプロジェクトで推奨されるわけではありません。
プロジェクトの規模や目的に応じて使い分けるのがベストです。
最適なユースケース
- 小規模なコンソールツール:特定のタスクを実行するだけのシンプルなツール。
- Azure Functions や AWS Lambda:サーバーレス環境での小さな実行単位。
- 学習・プロトタイピング:文法を確認したり、ライブラリの動作をテストしたりする場合。
- ASP.NET Core の Minimal API:最小限の記述でWeb APIを構築する場合。

従来の形式を維持すべきケース
一方で、大規模なエンタープライズアプリケーションや、多くの開発者が関わる複雑なプロジェクトでは、あえて従来のMainメソッド形式を採用することもあります。
コードの構造を厳格に保ち、どこがエントリポイントなのかを明示的に示したい場合には、従来の形式の方が可読性が高まることもあります。
まとめ
C# 9.0で導入されたトップレベルステートメントは、「C#はコード量が多くて難しい」というイメージを払拭する画期的な機能です。
ボイラープレートを排除することで、私たちはより本質的なロジックの実装に時間を割くことができるようになりました。
改めて重要なポイントを整理すると、以下の通りです。
Mainメソッドを省略し、直接処理を書き始められる。- 内部的にはコンパイラが従来通りの構造を補完している。
argsやawaitもそのまま使用可能。- プロジェクト内に1ファイルのみという制限や、記述順序のルールがある。
これからのC#開発では、特に小規模なツールやWeb APIの開発において、この機能が標準的な選択肢となっていくでしょう。
まだ試したことがない方は、ぜひ次回のプロジェクトでこの「軽快なC#」を体験してみてください。
