【C#】`dotnet run file.cs` で実行できるようになるらしい
どういうこと?
- .NET 10では
dotnet run file.csでC#が実行できるようになる(らしい)- .NET SDK 10 preview4の時点で使える
dotnet run file.cs
-
dotnet runやdotnet buildとは違い/binや/objが生成されない- ビルド成果物・中間物は作られません
-
通常のソース+プロジェクトファイルの形式にあとから変換できる
dotnet project convert file.cs
-
C# 14.0?にも新しい記法が入る模様
#!/usr/bin/dotnet run
#:sdk Microsoft.NET.Sdk.Web
#:property TargetFramework net10.0
#:property LangVersion preview
#:package System.CommandLine 2.0.0-*
Console.WriteLine("Hello, World!");
- 昔からある「C#スクリプト(拡張子が
*.csxのヤツ)」とは別物
dotnet run file.cs
これまでの dotnet run
昔からあるdotnet runコマンドはC#[1]の依存関係の解決・コンパイル・実行をまとめてやってくれる便利なコマンドです。
C#といえばコンパイル結果の実行ファイルを共有する、というイメージが強いですが、dotnet runコマンドがあるので、(SDKがインストールされている環境なら、)スクリプト配布のようにソースコードをそのまま配布してつかうこともできました。
ただし、これまでのdotnet runコマンドはソースファイル(*.cs)以外にプロジェクトファイル(*.csproj)が必要でした。
dotnet new consoleでテンプレートから作れば自動で作られるとはいえ、ファイルがたくさんあるのはスクリプト的な使い方をするには不便です。
ソースファイル(*.cs)を直接指定できるように
.NET 10以降のdotnet runコマンドではソースファイルを指定して実行できるようになります。プロジェクトファイル(*.csproj)は不要です[2]。
dotnet run file.cs
コマンドライン引数の指定の仕方はdotnet runと同じで、ソースファイル指定以外の引数がargsに渡されます。
dotnet run file.cs --option=xxx
ソースファイルを指定しなければ前と同じ挙動(プロジェクトファイルを探して利用)になります。
ビルド成果物・中間物(bin/obj)は生成されない
通常のdotnet runやdotnet buildではビルド結果(dllとかexe)や中間成果物が同じディレクトリの/binや/objに生成されます。
しかし今回の dotnet run file.csではビルド結果や中間物は生成されません。
exeもdllも存在せず、そのまま実行されます。ちょっとスクリプトっぽいですね。
とはいえビルドしていない訳ではなく、初回は依存関係のチェックもあるのでそこそこ時間が掛かります(初めてdotnet runを実行したときと同じくらい)。さすがにスクリプトほど早くはないです、残念!
/binや/objが作られないのでgitignoreに指定ミスってコミットしてしまった、というミスも防げますね[4]!
指定できるソースファイルは?
実行できるソースファイルはエントリポイントになれるファイルです。
エントリポイント、と言っても今のC#はトップレベルステートメントがあるので、
要はスクリプトみたいにいきなりコードが書かれてるソースファイルであればエントリポイントになります。
Console.WriteLine("Hello, World!");
エントリポイントじゃないcsファイルを指定すると、失敗します。
CSC : error CS5001:
プログラムは、エントリ ポイントに適切な静的 'Main' メソッドを含んでいません
プロジェクト "lib.csproj" のビルドが終了しました -- 失敗。
The build failed. Fix the build errors and run again.
//これはエントリポイントじゃない
public class Lib {}
C#の新しい記法: ignored directives
C#にも新しい記法が追加される予定です。
正確には2つあり、次の記号の組み合わせで始まる行はC#のコードとしては無視されます。
-
#!で始まる shebang directive -
#:で始まる ignored directive
#!/usr/bin/dotnet run
#:sdk Microsoft.NET.Sdk.Web
#:property TargetFramework net11.0
#:property LangVersion preview
#:package System.CommandLine 2.0.0-*
これらの行の前には文字を書くことはできません(BOMもNG)。
#!/usr/bin/dotnet run
#:sdk Microsoft.NET.Sdk.Web
#:property TargetFramework net11.0
#:property LangVersion preview
#:package System.CommandLine 2.0.0-*
Console.WriteLine("Hello, World!");
error CS1040: プリプロセッサ ディレクティブは行でスペース以外の最初の文字でなければなりません
プロジェクト "badignore.csproj" のビルドが終了しました -- 失敗。
C#のコードとして意味がなく、コンパイラやMS Buildなどに情報を与える用の記法になります。ここにcsprojで記載していた内容を書くことで、csprojが不要になります。
#! (shebang)
shebang directiveはシェルスクリプトなどでおなじみかと思います。
#!/usr/bin/dotnet run
つまりunix環境でパスを指定し、chmodすることでcsファイル単体で実行できるようになります。
【追記】macOS Sequoia 15.5の場合
#!/usr/bin/dotnet runでは動きません。
サンプルソース中の1行目は以下に書き換えます。
- #!/usr/bin/dotnet run
+ #!/usr/bin/env -S dotnet run
あとは実行権限を与えれば(chmod 755)、csファイルの指定だけで実行できます。
% chmod 755 file.cs
% ./file.cs
Hello, World!
#:
記法としては行頭の#:だけが追加されています。
しかし実際には#:sdkや#:propertyのように#:に続けてcsprojで記載していた内容を書くことになります。
| 記法 | csproj |
|---|---|
#:sdk *** |
<Project Sdk="***"> |
#:property XX YY |
<PropertyGroup><XX>YY</XX></PropertyGroup> |
#:package XX 1.0.0-* |
<ItemGroup><PackageReference Include="XX" Version="2.0.0-*" /></ItemGroup> |
今のところ指定できるのはsdk,property,packageの3つだけのようです。
通常のcsprojに変換できる
次のコマンドで普通のソースファイル(*.cs)とプロジェクトファイル(*.csproj)からなる普通の形式に変換できます。
dotnet project convert file.cs
file.cs
↓
file/
├ file.cs
└ file.csproj
ignored directivesの記載があった部分はソースファイルから削除され、csprojに変換されます。
#!/usr/bin/dotnet run
#:sdk Microsoft.NET.Sdk.Web
#:property TargetFramework net11.0
#:property LangVersion preview
#:package System.CommandLine 2.0.0-*
↓
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net11.0</TargetFramework>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.CommandLine" Version="2.0.0-*" />
</ItemGroup>
</Project>
C# Script / Replと何が違う?
C#には昔からC# Script(Roslyn Script)というスクリプト実行の仕組みがありました[6]。
- dotnet interactive
- VSCodeのPolyglot Notebooks
-
dotnet toolでインストールできる外部ツール
C# Scriptは名前の通りスクリプト実行なので、今回のものとは次の違いがあります
- ファイルの場合は専用の拡張子(
.csx)が必要 - 外部ライブラリ参照などで
#r等の専用記法が必要 dotnet run file.csxはできない
一方、dotnet run file.csのC#は普通のC#のソースコードです。
ignored directivesも必要なければ書く必要なく、これまでのC#のソースそのままが使えます。
ビルドにはやや時間がかかるため、スクリプトほどは早く動作せず[7]、REPL用途には向いてません。
他小ネタ
-
dotnet restore file.csやdotnet build file.csもできるとドキュメントにありますが、.NET SDK 10.0-preview4では動きませんでした。- 正式版では入る?
-
dotnet pack file.csやdotnet watch run file.csはサポートしない方針だそうです-
watchは欲しくなりそうな気も…
-
-
*.csの拡張子のファイルだけが対応しているようです[8]- F#とかVB.NETはサポートの想定がないのかもしれません
- まあF#には
dotnet fsiありますから要らないかも
- まあF#には
- F#とかVB.NETはサポートの想定がないのかもしれません
-
-blでバイナリログを出力するオプションが有効のようです - 追記:ビルドの高速化が検討されているようです
-
dotnet file.csで実行できるようになる事も検討されているようです
まとめ
- (たぶん).NET 10では
dotnet run file.csで単一ファイルからC#を実行できるようになり、プロジェクトファイル(.csproj)が不要に - ビルド成果物・中間ファイル(
/binや/obj)が生成されない - 実行は通常のC#コードと同様(スクリプトではない)ため、既存のC#の知識がそのまま活かせる
- 新たに導入される
#:や#!のディレクティブ記法でcsファイル内で依存関係やSDK指定が可能に -
dotnet project convert file.csで通常のプロジェクト構造に変換可能 - 既存のC# Script(
.csx)とは別物 - 現時点[9]では.NET SDK 10のプレビュー版で利用可能
追記
参考
- sdk/documentation/general/dotnet-run-file.md at main · dotnet/sdk
- csharplang/proposals/ignored-directives.md at main · dotnet/csharplang
-
正確にはF#なども ↩︎
-
内部的には仮想的なプロジェクトファイルが作られるような動きになるそうです ↩︎
-
dotnet new gitignoreすればいいだけですが… ↩︎ -
preview4時点では未実装 Support multiple files in file-based programs by jjonescz · Pull Request #48782 · dotnet/sdk ↩︎
-
なお、ややこしいですがUnityのC#も「C# Script」と言われていますがまた別物です ↩︎
-
とはいえdotnet-scriptも初回は同じくらい時間かかります ↩︎
-
2025-05-23 ↩︎
Discussion