> ## Content Index
> Fetch the complete content index at: https://nigzu.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Csharp 14 与 DotNET 10 的杀手级特性：成为并超越脚本语言
- URL: https://nigzu.com/csharp-dotnet-file-based-program-beyond-script/
- Published: 2025-12-16T08:06:43.000Z
- Updated: 2025-12-20T03:50:44.000Z
- Author: 宁嘉
- Tags: 砖工技术

当我首次在控制台运行 `dotnet run my-app.cs` 时，产生了一种久违的兴奋感，`C#` & `.NET` 这个传统上被视为笨重的编程语言与开发平台，突然拥有了脚本语言的灵魂。不再需要繁琐的 `.csproj` 文件，不再需要复杂的项目结构，一个 `.cs` 文件就能完整表达所有意图。这在开发体验上是非常不同的，更是 C# 生态的一次重要突破。

为此，我创建了一个开源项目 [CsharpFileScripts](https://github.com/code-gal/CsharpFileScripts?ref=nigzu.com)，专门探索这项技术的创新边界。今天，我想系统性地分享这项技术，以及它为什么值得你尝试。

## 什么是基于文件的 C# 程序？

[File-based C# Programs](https://learn.microsoft.com/zh-cn/dotnet/csharp/fundamentals/tutorials/file-based-programs?ref=nigzu.com) 是 C# 14 与 .NET 10 引入的革命性特性，允许将整个程序封装在单个 `.cs` 文件中，无需项目文件即可直接编译运行。

```csharp
#:package Colorful.Console@1.2.15

Colorful.Console.WriteAscii("Hello, File-based C#!");

```

保存为 `hello.cs`，终端执行 `dotnet run hello.cs` 即可看到华丽的 ASCII 艺术字输出。就是这么简单。

## 核心特性深度解析

### 1\. 顶级语句：脚本化的语法基础

这是 C# 9 引入的特性，但在基于文件的程序中，它的价值被发挥到了极致。它允许我们省略 `Program` 类和 `Main` 方法，直接从文件的第一行开始写逻辑——这正是 Python 或 JavaScript 开发者最熟悉的体验。

**传统 C# (繁琐):**

```csharp
using System;

namespace MyApp 
{
    class Program 
    {
        static void Main(string[] args) 
        {
            Console.WriteLine("Hello World");
        }
    }
}

```

**现代 C# 脚本 (清爽):**

```csharp
Console.WriteLine("Hello World");

```

这种语法糖不仅减少了视觉干扰，还带来两个脚本编写中极重要的便利：

1. **全局 `args`**：命令行参数 `args` 变量默认可用，无需声明。
2. **直接 `await`**：隐式支持异步入口，你可以直接在顶层写 `await HttpClient.GetAsync(...)`，无需为了异步操作专门包裹一个 `MainAsync`。

### 2\. 预处理器指令：在代码中定义项目

这是整个特性的技术基石。如果说顶级语句则赋予了它“脚本”的形态，预处理器指令赋予了单文件“项目”的能力。C# 编译器会忽略以 `#:` 开头的指令，但构建系统会解析它们生成临时的 `.csproj`。这巧妙地在保持语言纯净性的同时，赋予了单文件脚本定义完整项目能力：

#### `#:sdk` \- SDK 指定

```csharp
#:sdk Microsoft.NET.Sdk.Web           // Web 应用
#:sdk Aspire.AppHost.Sdk@9.4.1        // 支持指定版本

```

第一行对应 `<Project Sdk="...">`，后续行对应 `<Sdk Name="..." Version="..." />`

#### `#:property` \- MSBuild 属性

```csharp
#:property TargetFramework=net10.0
#:property LangVersion=preview
#:property PublishAot=false  // 设置为 true 可编译为原生二进制

```

任何传统项目中可用的 MSBuild 属性都支持，包括条件编译符号、输出路径等。

#### `#:package` \- NuGet 包引用

```csharp
#:package System.CommandLine@2.0.0-*
#:package Newtonsoft.Json@13.0.3

```

支持版本通配符和预发布版本，语法简洁直观。

#### `#:project` \- 项目引用

```csharp
#:project ../ClassLib/ClassLib.csproj
#:project ../AnotherProject           // 自动查找 .csproj

```

这项功能让单文件程序可以无缝融入现有解决方案架构。

### 3\. Shebang 支持：Unix 系统的原生脚本体验

在 Linux/macOS 上，C# 文件可以直接作为可执行脚本：

```csharp
#!/usr/bin/env dotnet
Console.WriteLine("I'm a real shell script now!");

```

赋予执行权限后：

```bash
chmod +x script.cs
./script.cs arg1 arg2

```

构建系统甚至支持无扩展名的文件（如 `./deploy`），只需这样写：

```csharp
#!/usr/bin/env dotnet
#:sdk Microsoft.NET.Sdk
// ... 你的代码

```

### 4\. 命令行参数与标准输入

可以通过预定义的 `args` 变量接收参数：

```csharp
if (args.Length > 0)
{
    Console.WriteLine($"参数: {string.Join(' ', args)}");
}

```

推荐使用 `--` 明确分隔参数，避免与 dotnet CLI 冲突：

```bash
dotnet run app.cs -- --my-option=value input.txt

```

标准输入处理同样简洁：

```csharp
while (Console.ReadLine() is string line && line.Length > 0)
{
    ProcessLine(line);
}

```

### 5\. 缓存机制

首次运行时，`dotnet` 主机会：

1. 在临时目录生成可执行文件
- Windows: `%TEMP%\dotnet\runfile\`
- Linux/macOS: `~/.dotnet/runfile/`
1. 后续执行时，仅当源文件变更才重新构建
2. 缓存不会自动清理，可通过 `dotnet clean your-file.cs` 手动清除

这种机制让脚本在保持快速启动的同时，避免了重复编译的开销。

## 项目实战：从演示看创新可能

在我的 [CsharpFileScripts](https://github.com/code-gal/CsharpFileScripts?ref=nigzu.com) 项目中，我探索了这项技术的多个创新应用场景：

### 场景 1：单文件 Web 应用与动态文档生成

这是我个人最喜欢的演示之一——`HelloTutorial.cs`。它将 Markdown 文档实时转换为美观的单页 HTML 教程，完整实现了语法高亮、响应式布局，带简单交互功能。

![HelloTutorial 演示](https://nigzu.com/file/HelloTutorial.png)

关键代码片段：

```csharp
#:sdk Microsoft.NET.Sdk.Web
#:package Markdig@0.34.0
#:package PrismDownloader@1.0.0

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => Results.Content("""
    <!DOCTYPE html>
    <form>
        <textarea name="markdown" placeholder="输入 Markdown">...</textarea>
        <button>生成教程</button>
    </form>
    """, "text/html"));

```

运行 `dotnet run HelloTutorial.cs`，一个功能完整的 Web 服务器立即启动。这种轻量级模式非常适合：

- 技术文档的快速预览
- 本地工具的内置帮助系统
- 轻量化内容管理系统

### 场景 2：交互式简历生成器

`HelloVitae.cs` 展示了如何将静态简历变为可交互的 Web 体验。无需部署复杂网站，运行脚本即可在本地展示个人主页。

![交互式简历](https://nigzu.com/file/HelloVitae.png)

### 场景 3：桌面自动化 RPA

`HelloWindowsNotePad.cs` 演示了如何调用 Windows API 实现机器人流程自动化，自动操作记事本完成文本输入、菜单操作等任务。这对系统管理员来说是极具价值的轻量级自动化方案。

### 场景 4：智能文件整理工具

`SmartMusicOrganizer.cs` 是一个实用的控制台应用，自动扫描音乐文件并按元数据分类整理。它展示了单文件程序作为系统管理工具的便捷性——复制到目标目录即可运行，无需安装。

![音乐整理工具](https://nigzu.com/file/SmartMusicOrganizer.png)

## 与其他脚本语言的对比

让我们客观比较基于文件的 C# 与其他脚本方案：

| 特性           | 基于文件的 C#          | Python   | Node.js  | PowerShell    | Bash      |
| ------------ | ----------------- | -------- | -------- | ------------- | --------- |
| **类型安全**     | ✅ 强类型编译时检查        | ⚠️ 运行时检查 | ⚠️ 运行时检查 | ⚠️ 运行时检查      | ❌ 无       |
| **性能**       | ✅ JIT/AOT 编译，接近原生 | 解释执行，较慢  | V8 优化，中等 | 解释执行，较慢       | 进程开销大     |
| **NuGet 生态** | ✅ 450K+ 企业级库      | PyPI 丰富  | npm 庞大   | 模块有限          | 工具分散      |
| **跨平台**      | ✅ 真正统一            | ✅ 良好     | ✅ 良好     | ⚠️ 依赖 PS Core | ❌ Unix 限定 |
| **IDE 支持**   | ✅ VS Code 完整      | ✅ 良好     | ✅ 良好     | ✅ 良好          | ⚠️ 有限     |
| **原生系统集成**   | ✅ P/Invoke 完整     | ⚠️ 需扩展   | ⚠️ 需扩展   | ✅ 深度集成        | ✅ 深度集成    |
| **部署**       | ⚠️ 通常不预装但部署灵活     | ✅ 通常已预装  | ✅ 通常已预装  | ✅ Windows 内置  | ✅ Unix 内置 |
| **启动速度**     | ⚠️ 首次编译较慢         | ✅ 快速     | ✅ 快速     | ✅ 快速          | ✅ 极速      |

**核心优势总结：**

1. **企业级生态**：访问完整的 .NET 运行时和 NuGet 库，这是其他脚本语言难以比拟的
2. **性能与安全的平衡**：编译时类型检查 + JIT/AOT 优化，既保证安全又不失性能
3. **渐进式复杂度**：从 10 行脚本到 10 万行系统，同一套语言和工具链
4. **现代化语言特性**：`async/await`、模式匹配、LINQ、源代码生成器等高级特性在脚本中完全可用
5. **真正的跨平台**：Windows、Linux、macOS 行为完全一致，无需适配
6. **“可进可退”的交付能力**：既可以像脚本一样轻便传输源码，也可以像 Go/Rust 一样编译成无依赖的独立应用。

劣势主要在于：

1. 首次运行有编译延迟
2. 语言本身相对冗长
3. 运行源码 (`.cs`) 需要安装 `.NET 10 SDK`（体积较大，200+ MB），但也可以：
- 运行编译后的程序 (`.dll`)，只需安装 `.NET Runtime`（体积较小，10+ MB）
- 运行独立发布程序 (`.exe`) , 零依赖（Self-contained 或 AOT）

## 不仅仅是脚本——三种分发模式

与其他脚本语言不同，基于文件的 C# 程序拥有 .NET 完整的构建管道支持，这意味着你可以根据场景选择三种截然不同的分发方式：

1. **源码分发**

  - **方式**：直接发送 `.cs` 文件。
  - **适用**：团队内部工具、CI/CD 脚本、开发者之间的分享。
  - **特点**：极轻量（几 KB），但在目标机器上需要安装 .NET SDK。
2. **自包含发布**

  - **方式**：`dotnet publish script.cs --self-contained true`
  - **适用**：分发给非开发人员的工具。
  - **特点**：无需目标机器安装 .NET Runtime/SDK。编译器会将运行时的一小部分（经过裁剪）和你的代码打包在一起。虽然体积较大（通常 20MB+），但确保了“解压即用”。
3. **原生 AOT 编译**

  - **方式**：`dotnet publish script.cs -p:PublishAot=true`
  - **适用**：高性能命令行工具、容器化微服务、受限环境。
  - **特点**：彻底脱离 .NET 运行时。直接编译为机器码，启动速度极快（毫秒级），内存占用极低，且难以被反编译。这是 Python 或 Node.js 难以企及的领域。

## 工具链与开发体验

### VS Code 完整支持

作为目前最佳开发环境：

- 安装 C# 和 C# Dev Kit 扩展
- 设置 `Dotnet > Projects: Enable File Based Programs` 启用预览功能
- 支持断点调试、IntelliSense、代码重构

### 命令行工具集

```bash
dotnet build script.cs      # 仅构建不运行
dotnet clean script.cs      # 清理构建缓存
dotnet restore script.cs    # 转换并生成 csproj 项目文件
dotnet publish script.cs    # 发布为独立可执行文件（.NET 10+ 支持）

```

### 配置文件支持

单文件程序支持配套 JSON 配置文件，实现更灵活的运行时管理：

```
my-web-app.cs
my-web-app.run.json      // 运行时配置（端口、环境变量等）
my-web-app.settings.json // 应用设置

```

对于 Web 项目，甚至可以携带 Blazor 组件，实现完整的单文件 SPA 应用。

### 当前限制

1. .NET 10 仍不支持单文件程序直接引用另一个单文件程序（需转换为 csproj）。
2. 指令必须出现在文件顶部，任何代码之前。
3. 在项目编译中遇到这些指令会生成警告（它们专属于 file-based 模式）。、
4. 最好保持单文件在 500 行以内，超出则考虑迁移到项目，如果是用AI生成的则随意。

## 未来展望

从 .NET 10 到 .NET 11 的路线图显示，这项技术正在快速演进：

1. **单文件互引用**：预告在 .NET 11 中实现，届时可以构建更复杂的单文件应用套件
2. **AI 生成友好**：简单的文件结构使其成为 AI 代码生成的理想目标，我已在项目中验证 AI 可完全自动化生成此类应用
3. **工具链完善**：Visual Studio 最终将获得原生支持，Visual Studio Code 的体验将持续优化

## 结语

基于文件的 C# 程序不是简单的语法糖，而是微软对开发者痛点的深刻回应。它保留了 C# 的所有优势——类型安全、卓越性能、庞大生态——同时赋予了脚本语言的便捷性。从教学原型到生产工具，从 Web 微服务到系统自动化，这项技术正在重塑我们使用 C# 的方式。

当你下次需要编写一个小工具时，不妨试试 `dotnet run script.cs`，体验编译型语言与脚本便捷性的完美融合，这很可能是 C# 14 带来的最具影响力的革新。