簡介
.NET 不斷進化,致力於讓開發體驗更簡單高效。最近,.NET CLI(命令列工具)提出了一項令人期待的新特性:可以直接執行 C# 原始檔,無需建立專案檔。這個特性稱為檔案式程式(File-based Programs),在 .NET 10 中將引入 dotnet run file 的支援,支援 dotnet sdk 直接執行,目前在 .NET 10 Preview 4 中已經可用,大家可以下載最新的 .NET 10 SDK 來試試看,之前自己動手寫的 dotnet-exec 部分功能可以使用原生的 SDK 支援了
什麼是檔案式程式
傳統 .NET 應用開發都需要一個專案檔(.csproj),哪怕只是執行一段簡單程式碼。檔案式程式則打破了這個門檻,允許你直接用命令列執行任意 C# 檔案:
echo 'Console.WriteLine("Hello C#!");' > hello.cs
dotnet run hello.cs
無需專案檔,無需複雜設定,像寫腳本一樣用 C#!

運作原理
- 當你執行
dotnet run file.cs時,CLI 會自動在記憶體中為這個檔案產生一個「隱含專案」(即虛擬專案檔),效果等同於基於dotnet new console範本建立的專案,這保證了你用單檔案腳本時,和用標準專案開發的行為一致,它的實作方式和 dotnet-exec 最近的 project compiler 很相似,不過實作得更好一些,實作的是虛擬專案檔,並未真實地建立檔案。 - 目標檔案下的所有
.cs檔案(包括子目錄)都會參與編譯(例如公共的工具類、資源等)。 - 相關的建構檔(如
Directory.Build.props)同樣會被自動套用。 - 如果你執行的檔案沒有進入點方法,會有錯誤提示,避免誤操作,示例如下:

更多用法
為了支援檔案程式的擴充,新增了
#:指令支援,在編譯專案檔時會自動忽略,針對檔案程式可以解析轉成專案檔裡的 sdk、引用和 project 屬性設定透過檔案頂部的特殊指令(如
#:sdk Microsoft.NET.Sdk.Web、#:package、#:property),你可以宣告 NuGet 相依套件或專案屬性。例如:
#:sdk Microsoft.NET.Sdk.Web #:package System.CommandLine@2.0.0-* #:property TargetFramework net10.0
我們可以指定 `#:sdk Microsoft.NET.Sdk.Web` 來建立一個單檔案的 WebApplication,
```csharp
#:sdk Microsoft.NET.Sdk.Web
var app = WebApplication.Create(args);
app.MapGet("/", () => "Hello World!");
await app.RunAsync();
透過 dotnet run webapi.cs 執行我們的單檔案 webapi

存取我們的 api

我們也可以引用 nuget package 和設定 property,示例如下:
#:sdk Microsoft.NET.Sdk.Web
#:package WeihanLi.Web.Extensions@2.1.0
#:property ManagePackageVersionsCentrally false
using WeihanLi.Web.Extensions;
var app = WebApplication.Create(args);
app.MapGet("/", () => "Hello World!");
app.MapRuntimeInfo();
await app.RunAsync();
同樣地,執行 dotnet run webapi.cs

- 當你的腳本變複雜,需要更多自訂時不想使用檔案程式,只需一條命令即可將其轉換為標準專案,CLI 會自動產生
.csproj檔案,並移轉相關設定,程式碼行為不會改變:
dotnet project convert webapi.cs
轉換之後的專案如下,也可以直接使用 dotnet run 執行

支援 Linux/Unix 下的 shebang(#!),我們可以讓 C# 腳本像 Bash/Python 一樣直接執行,可以執行 ./hello.cs
#!/usr/bin/dotnet run
Console.WriteLine("Hello, .NET!");

未來功能
透過 dotnet run file.cs 直接執行 C# 檔案的提案,為 .NET 帶來了靈活強大的腳本體驗。設計文件中也展望了許多未來可能的增強,使檔案式程式在 .NET 生態中變得更實用,後續還有一些功能特性
1. 目標路徑的擴充支援
- 資料夾作為目標:允許將資料夾作為
dotnet run的目標(如:dotnet run ./my-app/),可直接執行該資料夾下的主進入點。 - 標準輸入與內嵌程式碼:支援
dotnet run --cs-from-stdin透過標準輸入讀取 C# 程式碼,或用dotnet run --cs-code 'Console.WriteLine("Hi")'實現原始程式碼腳本。
2. 統一命令列參數
- 目錄與檔案選項:引入
--directory、--file或統一的--path選項,讓檔案式和專案式程式的命令體驗一致。 - 多進入點支援:增加如
--entry等參數,便於在多程式目錄中選擇指定進入點執行。
3. 增強整合與一致性
- 成長前後的無縫體驗:確保無論是檔案式還是升級為專案式,
dotnet run等命令都能順暢執行。 - 通用選項:未來可提供一個適用於專案或檔案兩種格式的統一參數,讓格式切換更加平滑。
4. 效能與易用性提升
- 選擇性包含檔案:透過參數或指令控制包含哪些檔案,減少意外包含大量檔案帶來的困擾和效能負擔。
- 巢狀檔案錯誤提示:如子目錄包含過多
.cs檔案或.csproj檔案時,可考慮報錯或警告,避免無意間編譯大量內容。
5. 多進入點場景的實作優化
- 專案結構生成:優化多進入點目錄「成長」為專案時的結構生成,合理劃分專案子目錄,共用程式碼處理更清晰。
- 進階存取控制:探索
InternalsVisibleTo等特性用於更好的程式碼共用,並考慮未來 C# 語言的增強。
6. Shebang 與 Shell 支援
- 專用可執行檔:可能會發佈
dotnet-run或dotnet-run-file可執行檔,提升 shebang(#!)在不同 shell 環境下的相容性,讓腳本跨平台直接執行。 - 支援
/usr/bin/env:研究如何規避 shell 使用 shebang 時的參數傳遞限制,提高 CLI 腳本的易用性。
7. 更多檔案式程式命令支援
- 建構與還原:擴充
dotnet restore file.cs、dotnet build file.cs等命令,便於 IDE 和 CI 整合檔案式程式。 - 套件管理:
dotnet package add可直接向 C# 檔案頂部新增#:package指令,簡化腳本相依性管理。
8. 明確檔案匯入
- 匯入指令:未來可能支援
#import ./another-file.cs等指令,明確指定需包含的 C# 檔案,開發者控制更靈活。
其他
目前我們還需要使用 dotnet run hello.cs,後續會可以簡化成 dotnet hello.cs,還可以執行原始程式碼,期待後面更好用的特性了~~
更多資訊可以參考官方文件介紹: https://github.com/dotnet/sdk/blob/main/documentation/general/dotnet-run-file.md
感覺有點不完美的是又建立了一種新的 nuget package 引用語法,和 dotnet-script 裡 nuget: package@version 不同,和 dotnet-script 不太相容
目前還不支援自訂進入點,後面如果能夠支援自訂進入點方法就更好了,期待~~
最後在 build 大會上有一個 dotnet run file 的介紹影片,大家感興趣可以看一下
【影片可點擊原公眾號查看】
參考資料
- • Document: https://github.com/dotnet/sdk/blob/main/documentation/general/dotnet-run-file.md
- • File-Based Programs IDE Spec: https://github.com/dotnet/roslyn/blob/main/docs/features/file-based-programs-vscode.md
- • Shebang in Unix: https://en.wikipedia.org/wiki/Shebang_(Unix)
- • https://github.com/dotnet/sdk/pull/46915/files
- • https://github.com/dotnet/sdk/pull/48782/files
- • https://github.com/dotnet/sdk/pulls?q=is%3Apr+label%3AArea-run-file+is%3Aclosed