mcpField
C
csharp-scripts

csharp-scripts

github.com/dotnet开发5.8k4.0k 次安装1 天前更新
代码仓库

关于 csharp-scripts

为开发者提供使用 .NET 10 及更高版本构建和运行基于文件的 C# 小型应用的工作流,适合概念验证、原型和轻量工具。涵盖单文件与多文件组织、指令和旧版 SDK 的回退方案。

主要功能

  1. 01创建顶级语句入口文件
  2. 02用指令添加 NuGet 包和属性
  3. 03纳入辅助文件或引用项目
  4. 04通过 dotnet 运行或清理应用
  5. 05检查 SDK 版本并提供旧版回退

适用场景

  1. 01快速试验 C# 语言特性或 API
  2. 02在整合进大型项目前验证逻辑
  3. 03从少量 .cs 文件构建小型工具

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dotnet/skills --skill csharp-scripts

安装后在 Claude Code 中输入/csharp-scripts确认已加载。

详细介绍

基于文件的 C# 应用

适用场景

  • 使用基于文件的应用快速测试 C# 概念、API 或语言功能
  • 在将逻辑集成到更大的项目之前进行原型开发
  • 使用一个入口文件和几个辅助 .cs 文件构建小型实用工具

不适用场景

  • 用户需要与语言无关的快速脚本、一次性计算,或类似 shell/Python/PowerShell 的自动化
  • 用户需要完整项目、集成到解决方案,或在现有应用中添加项目引用
  • 用户正在现有 .NET 解决方案中工作,并希望在其中添加代码
  • 应用规模足够大,需要将项目结构、构建自定义、测试或发布配置放在 .csproj 中

输入

输入必填描述
C# 代码或意图是要运行的代码,或对基于文件的应用功能的描述

工作流

步骤 1:检查 .NET SDK 版本

运行 dotnet --version,确认已安装 SDK,并记下完整版本号,包括功能带。基于文件的应用需要 .NET 10 或更高版本。#:include、#:exclude 和传递指令处理需要 SDK 10.0.300 或更高版本;SDK 10.0.100/10.0.200 版本可以运行单文件应用,但不支持这些多文件指令。如果版本低于 10,请改为按照旧版 SDK 的回退方案操作。

步骤 2:编写应用文件

使用顶级语句创建入口 .cs 文件。将其放在任何现有项目目录之外,以避免与 .csproj 文件冲突。

#!/usr/bin/env dotnet
// hello.cs
Console.WriteLine("Hello from a file-based app!");

var numbers = new[] { 1, 2, 3, 4, 5 };
Console.WriteLine($"Sum: {numbers.Sum()}");

指南:

  • 使用顶级语句(不要添加 Main 方法、类或命名空间样板代码)
  • 将 using 指令放在文件顶部(如果存在 #! 行和任何 #: 指令,则放在它们之后)
  • 将类型声明(类、记录、枚举)放在所有顶级语句之后
步骤 3:运行应用
dotnet hello.cs

此命令会自动构建并运行文件。结果会被缓存,因此后续运行速度很快。在 -- 后传递参数:

dotnet hello.cs -- arg1 arg2 "multi word arg"
步骤 4:添加指令(如有需要)

将指令放在文件顶部(可选 shebang 行之后),并置于任何 using 指令或其他 C# 代码之前。所有指令都以 #: 开头。

#:package — NuGet 包引用

除非应用有意使用中央包管理,否则请指定版本。如果可以使用最新可用版本,请使用 @*(预发布版本则使用 @*-*):

#:package [email protected]

using Humanizer;

Console.WriteLine("hello world".Titleize());
#:property — MSBuild 属性

内联设置任意 MSBuild 属性。语法:#:property PropertyName=Value

#:property AllowUnsafeBlocks=true
#:property PublishAot=false
#:property NoWarn=CS0162

支持 MSBuild 表达式和属性函数:

#:property LogLevel=$([MSBuild]::ValueOrDefault('$(LOG_LEVEL)', 'Information'))

常用属性:

属性用途
AllowUnsafeBlocks=true启用 unsafe 代码
PublishAot=false禁用原生 AOT(默认启用)
NoWarn=CS0162;CS0219禁止显示特定警告
LangVersion=preview启用预览版语言功能
InvariantGlobalization=false启用特定于区域性的全球化
#:project — 项目引用

通过相对路径引用另一个项目:

#:project ../MyLibrary/MyLibrary.csproj
#:ref — 基于文件的应用引用

当另一个 .cs 文件应编译为单独的程序集,而不是纳入同一编译时,可将其引用为单独的基于文件的应用项目。对于应与入口点共用同一程序集的普通辅助文件,请使用 #:include;如果需要类似项目引用的边界,请使用 #:ref。

#:property ExperimentalFileBasedProgramEnableRefDirective=true
#:ref ../Shared/Formatter.cs

Console.WriteLine(Formatter.Title("hello world"));

指南:

  • 被引用的文件会作为独立的虚拟项目编译,并作为项目引用添加。
  • 如果被引用的文件是没有顶级语句的库,请在该文件中添加 #:property OutputType=Library。
  • 引用应用需要使用的成员必须是 public;程序集边界外无法访问 internal 成员。
  • #:ref 具有传递性:被引用的文件可以包含自己的 #:ref 和其他 #: 指令。
  • 相对路径以包含该指令的文件所在位置为基准解析。
  • 某些 SDK 版本需要设置 #:property ExperimentalFileBasedProgramEnableRefDirective=true;如果 SDK 无需该属性也能接受 #:ref,请移除该属性。
#:sdk — SDK 选择

覆盖默认 SDK(Microsoft.NET.Sdk):

#:sdk Microsoft.NET.Sdk.Web
#:include 和 #:exclude — 多文件应用

在 .NET SDK 10.0.300 及更高版本中,基于文件的应用可以在同一虚拟项目中包含其他文件。使用这些指令前,请检查完整的 dotnet --version 输出;10.0.100 或 10.0.200 SDK 虽然也是 .NET 10,但不支持这些指令。使用 #:include 包含辅助源文件和受支持的资产,并使用 #:exclude 从包含模式或默认项集中移除文件。

#!/usr/bin/env dotnet
#:include Helpers.cs
#:include Models/*.cs
#:exclude Models/Generated/*.cs

Console.WriteLine(Formatter.Title("hello world"));

指南:

  • 将传递给 dotnet 的文件视为入口点;在其中编写顶级语句。
  • 在包含的 .cs 文件中放置类、记录和枚举等声明。
  • 优先使用 Helpers.cs 或 Models/*.cs 等显式 glob,而不是宽泛的递归 glob。
  • 路径以包含该指令的文件所在位置为基准解析。
  • 也会处理非入口点 C# 文件中的包含指令,因此辅助文件可以声明自己的 #:package、#:property、#:sdk、#:project、#:ref、#:include 或 #:exclude 指令。
  • 除非指令类型明确支持重复,否则请避免在包含的文件中重复声明指令;重复的 #:package、#:property、#:sdk、#:include 和 #:exclude 条目可能导致失败。
  • 应用使用 #:include 时,在类 Unix 系统上,请在入口点文件中添加 shebang(#!/usr/bin/env dotnet),以便工具明确入口点。Shebang 文件请使用 LF 换行符,且不要包含 BOM。

示例布局:

scratch/
    hello.cs
    Helpers.cs
    Models/
        Person.cs
#!/usr/bin/env dotnet
// hello.cs
#:include Helpers.cs
#:include Models/*.cs

var person = new Person("Ada");
Console.WriteLine(Formatter.Title(person.Name));
// Helpers.cs
static class Formatter
{
    public static string Title(string value) => value.ToUpperInvariant();
}
// Models/Person.cs
record Person(string Name);
第 5 步:清理

用户完成后,移除应用文件。若要清除缓存的构建产物:

dotnet clean hello.cs

Unix shebang 支持

在 Unix 平台上,可让 .cs 文件直接执行:

  1. 将 shebang 添加为文件的第一行:

    #!/usr/bin/env dotnet
    Console.WriteLine("I'm executable!");
    
  2. 设置执行权限:

    chmod +x hello.cs
    
  3. 直接运行:

    ./hello.cs
    

添加 shebang 时请使用 LF 换行符(而不是 CRLF)。此指令在 Windows 上会被忽略。

源生成 JSON

基于文件的应用默认启用本机 AOT。JsonSerializer.Serialize<T>(value) 等基于反射的 API 在 AOT 环境下会于运行时失败。请改用源生成序列化:

using System.Text.Json;
using System.Text.Json.Serialization;

var person = new Person("Alice", 30);
var json = JsonSerializer.Serialize(person, AppJsonContext.Default.Person);
Console.WriteLine(json);

var deserialized = JsonSerializer.Deserialize(json, AppJsonContext.Default.Person);
Console.WriteLine($"Name: {deserialized!.Name}, Age: {deserialized.Age}");

record Person(string Name, int Age);

[JsonSerializable(typeof(Person))]
partial class AppJsonContext : JsonSerializerContext;

转换为项目

当基于文件的应用不再适合此工作流时,请将其转换为完整项目:

dotnet project convert hello.cs

.NET 9 及更早版本的备用方案

如果 .NET SDK 版本低于 10,则无法使用基于文件的应用。请改用临时控制台项目:

mkdir -p /tmp/csharp-file-based-app && cd /tmp/csharp-file-based-app
dotnet new console -o . --force

将生成的 Program.cs 替换为应用内容,然后使用 dotnet run 运行。使用 dotnet add package <name> 添加 NuGet 包。完成后移除该目录。

验证

  • dotnet --version 报告 10.0 或更高版本(或使用回退路径)
  • 如果应用使用了 #:include、#:exclude,或来自所含文件的传递指令,dotnet --version 报告 SDK 10.0.300 或更高版本
  • 应用编译无错误(可使用 dotnet build <file>.cs 显式检查)
  • dotnet <file>.cs 生成预期输出
  • 多文件应用包含所有必需的辅助文件,并排除非预期的匹配项
  • 会话结束后清理应用文件和缓存的构件

常见问题

问题解决方案
.cs 文件位于包含 .csproj 的目录中将应用移到项目目录之外,或使用 dotnet run --file file.cs
#:package 未指定版本指定版本:#:package [email protected],或使用 @* 获取最新版本
#:property 语法错误使用 PropertyName=Value,= 两侧不加空格,也不加引号:#:property AllowUnsafeBlocks=true
指令位于 C# 代码之后所有 #: 指令都必须紧接在可选的 shebang 行(如有)之后,并位于任何 using 指令或其他 C# 语句之前
辅助文件未编译在入口点文件中添加 #:include Helper.cs 或合适的 glob 模式
共享文件需要程序集边界使用 #:ref Shared.cs 替代 #:include Shared.cs;如果引用的文件没有入口点,则在其中设置 #:property OutputType=Library
宽泛的 include 引入了不相关文件优先使用精确的 include 模式,并使用 #:exclude 排除生成文件、备份文件或实验性文件
所含文件中存在重复指令确保入口点和所含 C# 文件中的 package、property、SDK、include 和 exclude 指令均不重复
基于反射的 JSON 序列化失败使用源生成的 JSON 和 JsonSerializerContext(参见源生成的 JSON)
构建行为异常或出现版本错误基于文件的应用会继承父目录中的 global.json、Directory.Build.props、Directory.Build.targets 和 nuget.config。如果继承的设置存在冲突,请将应用移至独立目录

更多信息

如需了解基于文件的应用的完整参考,请参见 https://learn.microsoft.com/en-us/dotnet/core/sdk/file-based-apps。

评论

支持 Markdown