【C#】`dotnet run file.cs` で実行できるようになるらしい

に公開

https://www.youtube.com/watch?v=98MizuB7i-w

どういうこと?

  • .NET 10ではdotnet run file.csでC#が実行できるようになる(らしい)
    • .NET SDK 10 preview4の時点で使える
dotnet run file.cs
  • dotnet rundotnet buildとは違い/bin/objが生成されない

    • ビルド成果物・中間物は作られません
  • 通常のソース+プロジェクトファイルの形式にあとから変換できる

    • dotnet project convert file.cs
  • C# 14.0?にも新しい記法が入る模様

ignored directives
#!/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!");

dotnet run file.cs

これまでの dotnet run

昔からあるdotnet runコマンドはC#[1]の依存関係の解決・コンパイル・実行をまとめてやってくれる便利なコマンドです。

https://learn.microsoft.com/ja-jp/dotnet/core/tools/dotnet-run

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#はトップレベルステートメントがあるので、
要はスクリプトみたいにいきなりコードが書かれてるソースファイルであればエントリポイントになります。

これだけでエントリポイント(file.cs)
Console.WriteLine("Hello, World!");

エントリポイントじゃないcsファイルを指定すると、失敗します。

例 dotnet run lib.cs
CSC : error CS5001:
プログラムは、エントリ ポイントに適切な静的 'Main' メソッドを含んでいません
プロジェクト "lib.csproj" のビルドが終了しました -- 失敗。

The build failed. Fix the build errors and run again.
例 lib.cs
//これはエントリポイントじゃない
public class Lib {}

C#の新しい記法: ignored directives

C#にも新しい記法が追加される予定です。

正確には2つあり、次の記号の組み合わせで始まる行はC#のコードとしては無視されます

ファイル先頭に記載
#!/usr/bin/dotnet run
#:sdk      Microsoft.NET.Sdk.Web
#:property TargetFramework net11.0
#:property LangVersion preview
#:package  System.CommandLine 2.0.0-*

これらの行の前には文字を書くことはできません(BOMもNG)。

badignore.cs 空行があると…

#!/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

https://ja.wikipedia.org/wiki/シバン_(Unix)

つまりunix環境でパスを指定し、chmodすることでcsファイル単体で実行できるようになります

【追記】macOS Sequoia 15.5の場合

#!/usr/bin/dotnet runでは動きません。
サンプルソース中の1行目は以下に書き換えます。

file.cs
- #!/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に変換されます。

変換前のdirectives
#!/usr/bin/dotnet run
#:sdk      Microsoft.NET.Sdk.Web
#:property TargetFramework net11.0
#:property LangVersion preview
#:package  System.CommandLine 2.0.0-*

file.csproj
<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]

https://zenn.dev/zead/articles/first-polyglots

C# Scriptは名前の通りスクリプト実行なので、今回のものとは次の違いがあります

一方、dotnet run file.csのC#は普通のC#のソースコードです。
ignored directivesも必要なければ書く必要なく、これまでのC#のソースそのままが使えます。

ビルドにはやや時間がかかるため、スクリプトほどは早く動作せず[7]、REPL用途には向いてません。

他小ネタ

  • dotnet restore file.csdotnet build file.csもできるとドキュメントにありますが、.NET SDK 10.0-preview4では動きませんでした。
    • 正式版では入る?
  • dotnet pack file.csdotnet watch run file.csはサポートしない方針だそうです
    • watchは欲しくなりそうな気も…
  • *.csの拡張子のファイルだけが対応しているようです[8]
    • F#とかVB.NETはサポートの想定がないのかもしれません
      • まあF#にはdotnet fsiありますから要らないかも
  • -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のプレビュー版で利用可能

追記

https://zenn.dev/inuinu/articles/before-csharp13-dotnet-run-file

参考

脚注
  1. 正確にはF#なども ↩︎

  2. 内部的には仮想的なプロジェクトファイルが作られるような動きになるそうです ↩︎

  3. Build outputs ↩︎

  4. dotnet new gitignoreすればいいだけですが… ↩︎

  5. preview4時点では未実装 Support multiple files in file-based programs by jjonescz · Pull Request #48782 · dotnet/sdk ↩︎

  6. なお、ややこしいですがUnityのC#も「C# Script」と言われていますがまた別物です ↩︎

  7. とはいえdotnet-scriptも初回は同じくらい時間かかります ↩︎

  8. Add basic support for 'dotnet run file.cs' #46915 ↩︎

  9. 2025-05-23 ↩︎

Discussion