【実験】C#13.0以前でdotnet run file.csを動かす

に公開

C#の新記法だけど…

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

dotnet CLIの新コマンド、dotnet run file.csではプロジェクトファイル(*.csproj)いらずで実行できるようにするため、「ignored directive」という記法がC#に追加されています。

ignored directives
#!/usr/bin/env -S dotnet run
#:sdk      Microsoft.NET.Sdk.Web
#:property TargetFramework net10.0
#:property LangVersion preview
#:package  System.CommandLine 2.0.0-*

既にpreviewに実装済み[1]なので、C#14.0の内容ってことになるっぽいですが、C#の文法的には意味のないもの(無視されるもの)です。

なので、実はC#13.0以前のバージョンでも使えます

ただし、ignored directive、dotnet run file.csは .NET SDKのサポートがいる ので、.NET SDK 10-preview 4以降が必要です。

古いバージョンのC#でdotnet run file.csする方法

  • SDKは.NET 10 SDK以降にする
  • エントリーポイントのコードをトップレベルステートメントで記述する
  • #:propertyLangVersion対応可能なバージョンの範囲で下げる
  • #:propertyTargetFrameworkを有効なバージョンを指定する

SDKは.NET 10 SDK以降にする

C#は言語バージョンとランタイム(.NET Runtime)のバージョンには対応はあるものの、必ず合わせないといけないというわけではありません。

たとえば、

  • 最新のランタイム.NET 9で古いC#8.0を使う
  • 古い.NET Framework 4.8で最新のC#13.0を使う

とかが(一部制限はあるものの)できます。

ignored directive、dotnet run file.csは .NET SDK 10 からなのでこれにします。ただし、言語バージョンは14から落とします。

エントリーポイントのコードをトップレベルステートメントで記述する

dotnet run file.csで指定できるC#コードはトップレベルステートメントで記述されたコードです。

トップレベルステートメントはC#9.0で導入されたので、
つまり、C#9.0以降なら使えるということになります。

C#9.0は2020年公開で結構前なので、(C#自体は)少し前の古いC#でもいいということになります。

#:propertyLangVersion対応可能なバージョンの範囲で下げる

通常、csprojでLangVersionを指定すればC#のバージョンを指定できます。dotnet run file.csで動くようにするにはdirectiveにLangVersionを指定します。

C# 10.0の場合
#!/usr/bin/env -S dotnet run
#:property LangVersion 10

Console.WriteLine("Hello, World!");

#:propertyTargetFrameworkを有効なバージョンを指定する

C#プログラムが実行される.NETランタイムも、古いバージョンを指定することでそのバージョンで実行できるようです。

.NET Framework 4.8.xで動かす
#!/usr/bin/env -S dotnet run
#:property LangVersion 9
#:property ImplicitUsings disable
#:property TargetFramework net48

using System;
Console.WriteLine("Hello, World!");

サポートが切れたバージョンのランタイムも指定できますが、Warningがでます。また未インストールのランタイムは指定してビルド自体まではできるものの、実行時に失敗します。

実用性は?

あまりありません!

SDKは最新だけど、言語バージョンはプロジェクトの方針で古いまま維持したい、というケースくらい…?
(まあでもそんなプロジェクトで新しいdotnet run files.csを使うのか???)

あとは、古い環境でどう動くかを簡単に書いたコードでテストしたい、みたいなときにも使えるかもしれません。
dotnet run files.csで指定できるファイルはフォルダ分け不要で同じフォルダに置いてあってもいいので、簡易テストには向いてます。

脚注
  1. https://github.com/dotnet/roslyn/blob/main/docs/Language Feature Status.md#working-set-c ↩︎

Discussion