.NET 11 预览 3:开发人员的评论
.NET 11即将在计划的2026年11月GA发布前约六个月发布第三个预览,与主要是基础架构的预览1和2不同,预览3是您实际感受到发布形态的地方。
运行时异步不再是一个"预览功能门"实验,JIT又拾到了一批免费优化,ASP.NET Core开箱即用Zstandard,C# 15的联合类型 - 人们过去十几年一直在询问的语言特性。
这不是一个LTS版本,.NET 11是下一个标准期限支持版本,支持24个月,这已经改变了您是否要升级的计算。 以下是您作为开发者真正值得关注的内容,以及仍然存在的粗糙边缘。
C# 15联合类型:大的一项
如果您一直在编写OneOf<T1, T2>库、手动编写封装的记录层次结构,或只是羡慕F#开发人员,这是重点。C# 15引入了一个union关键字,声明一个值是固定类型集中的一种,并通过编译器强制的穷尽性检查。 联合类型在预览2中到来; 预览3围绕它们完善了IDE支持。
C#团队的方法更接近于类型联合,而不是F#的判别联合:成员类型是您单独定义的现有类型,而不是嵌套在联合声明中的标记案例。 联合本质上是一个包装对象的结构,并限制了可以放入的内容。 从调用站点来看,它感觉原生——从成员类型隐式转换为union,穷尽的switch表达式遍历Pet.Value,并且当编译器可以看到所有情况时,不需要默认分支。
[Union]
public partial struct Pet : IUnion
{
public Pet(Dog dog);
public Pet(Cat cat);
public Pet(Bird bird);
}
string Describe(Pet pet) => pet.Value switch
{
Dog d => $"Dog named {d.Name}",
Cat c => $"Cat ({c.Color})",
Bird b => $"Bird, {b.Species}",
// no default - compiler knows the set is closed
};
[Union]
public partial struct Pet : IUnion
{
public Pet(Dog dog);
public Pet(Cat cat);
public Pet(Bird bird);
}
string Describe(Pet pet) => pet.Value switch
{
Dog d => $"Dog named {d.Name}",
Cat c => $"Cat ({c.Color})",
Bird b => $"Bird, {b.Species}",
// no default - compiler knows the set is closed
};
<Union>
Public Partial Structure Pet
Implements IUnion
Public Sub New(dog As Dog)
End Sub
Public Sub New(cat As Cat)
End Sub
Public Sub New(bird As Bird)
End Sub
End Structure
Function Describe(pet As Pet) As String
Return pet.Value Select Case
Case d As Dog
Return $"Dog named {d.Name}"
Case c As Cat
Return $"Cat ({c.Color})"
Case b As Bird
Return $"Bird, {b.Species}"
' no default - compiler knows the set is closed
End Select
End Function优点是显而易见的:封闭类型,无无效状态,编译时穷尽性检查而不是NotImplementedExceptionat凌晨三点。 添加一条鲨鱼到联合中,每个在Pet上的切换都会亮起警告,直到您处理它。
缺点也同样真实,值得在任何诚实的审查中标记。 暴露的对象Value属性是一种气味 - GitHub上有一个关于隐藏它的更安全类型的方法的讨论。 公共构造函数隐式定义了联合接受的类型,这既不可发现也不明确。 F#互操作性未解决(这两种模型根本不同)。 更广泛的穷尽性故事仍有空白:闭合层次和闭合枚举,这两个提案将完善这幅图景,仍然是提案。 单独的联合确实是不错的。 联合加上闭合枚举加上闭合层次将是一个世代转变。 我们还没完全到那里。
运行时异步V2和JIT改进
运行时异步是.NET重新设计异步/等待的方式。 而不是让C#编译器为每个异步方法发出一个状态机类,运行时本身管理暂停和恢复。 可见的收益:更清晰的堆栈跟踪,较小的分配,以及一个调试器,不必在MoveNext帧滚动过去以找到您自己的代码。
在Preview 3中,Runtime Async消除了EnablePreviewFeatures的要求。 您仍然需要切换功能开关 - <Features>runtime-async=on</Features> - 但不再需要将每个API调用都置于预览模式。 NativeAOT和ReadyToRun支持也在此预览中上线,这关闭了JIT和AOT场景之间的差距。 延续对象被更积极地重用,并且没有更改的局部变量不会在暂停之间被保存。 在异步密集的代码路径中 - 比如Kestrel管道或EF Core查询工作者 - 这在分配压力上是一个显著的下降。
JIT获得了常规的批次"您的现有代码现在更快,什么也不做":
- 多目标切换表达式,如x是0或1或2或3或4现在折叠成无分支检查。
- 在值[^1] + 值[^2]模式上的边界检查更积极地被消除,循环中常见的i + cns < len情况被干净地折叠。
- 无符号整数到浮点数和无符号整数到双精度浮点数的转换在预AVX-512 x86硬件上更快 - 小众,但真实如果您使用旧盒子。
WebAssembly用户可以直接在运行时加载WebCIL负载,更好的调试符号,以及float[] / Span<float> / ArraySegment<float>的编组处理,没有往返开销。 这些中没有一个是单个戏剧性的,但它们共同构成了使Blazor WASM感受不那么妥协的复利工作。
问题是硬件底线。 .NET 11提高了x86/x64和Arm64的最低指令集要求。Apple Silicon和大多数Linux SBC都没问题 - Arm64上的ReadyToRun目标只是增加了LSE - 但非常旧的x86硬件不支持。 在您假设就地升级之前审计您的设备。
ASP.NET Core和Blazor
Zstandard是这里的亮点。 ASP.NET Core现在支持zstd进行响应压缩和请求解压缩,并且当您添加中间件时默认启用。 配置是您所期望的形状:
builder.Services.AddResponseCompression();
builder.Services.AddRequestDecompression();
builder.Services.Configure<ZstandardCompressionProviderOptions>(options =>
{
options.CompressionOptions = new ZstandardCompressionOptions { Quality = 6 };
});
builder.Services.AddResponseCompression();
builder.Services.AddRequestDecompression();
builder.Services.Configure<ZstandardCompressionProviderOptions>(options =>
{
options.CompressionOptions = new ZstandardCompressionOptions { Quality = 6 };
});
Imports Microsoft.Extensions.DependencyInjection
builder.Services.AddResponseCompression()
builder.Services.AddRequestDecompression()
builder.Services.Configure(Of ZstandardCompressionProviderOptions)(Sub(options)
options.CompressionOptions = New ZstandardCompressionOptions With {.Quality = 6}
End Sub)对于向已经使用zstd的客户端提供JSON或文本有效负载的API - 在移动和gRPC相关生态系统中越来越常见 - 这是在不依赖于第三方库的情况下的可测量带宽胜利。 同样值得注意的是,这是一种社区贡献,而不是微软内部的贡献,这是一个健康的信号。
Blazor的Virtualize<TItem>终于不再假设每一行的高度相同。 这是一个长久以来的烦恼:任何具有可变内容的列表 - 评论,聊天消息,任何带有换行文本的东西 - 都需要手动解决方法。 现在组件在运行时测量项目。Preview 3版本还修复了一些Blazor的bug:Virtualize中的空引用、带有overflow-x的滚动容器检测、发布的WASM应用中的Web Worker模板、IJSObjectReference的泄漏。 单独来说很小,整体上这是一个稳定框架信号的清理。
Kestrel也开始在不等待控制流和SETTINGS帧的情况下处理HTTP/3请求,这减少了新连接上的首次请求延迟。 如果您一直在测量HTTP/3 P99并看到冷启动尾巴的异常,这是您的修复措施。
.NET MAUI
预览3中的MAUI主要是关于关闭让它感觉像测试版太久的差距。 Map控件获得了图钉聚类、自定义图钉图标、自定义JSON样式,以及对圆形、多边形和折线的点击事件——所有这些都是实际生产地图UI需要的,此前每个平台都需要自定义处理程序。 现在可以使用内置的LongPressGestureRecognizer,而不是自己滚动。 默认启用隐式XAML命名空间声明,这减少了每个文件顶部的样板。
平台一致性得到了提升:Permissions.PostNotifications现在在iOS上实现(之前仅限于Android),Android获得对Android 17和API级别37的预览支持。
诚实的评估:这是稳定,明智的迭代,而不是重新发明。 2026年的MAUI比2023年的MAUI处于更好的位置,但如果您在其生命周期早期离开它,单单预览3不会让您返回。 如果您已经在使用MAUI,这正是您想要的生活质量变化。
SDK、CLI和.NET观察
这是小事情积累的地方。有几个是我认为真正改变每日工作流的:
.NET sln现在可以直接从CLI创建和编辑解决方案过滤器(.slnf)。 对于monorepos和大型Microsoft风格的解决方案,打开一个200项目的SLN以处理其中三个一直是一个真正的成本。现在您可以从终端进行范围限定:
dotnet new slnf --name MyApp.slnf
dotnet sln MyApp.slnf add src/Lib/Lib.csprojdotnet new slnf --name MyApp.slnf
dotnet sln MyApp.slnf add src/Lib/Lib.csproj文件为基础的应用程序(.NET run app.cs工作流)终于支持#:include,这意味着C#脚本可以将助手拆分为单独的文件。 与Roslyn中的指令编辑器补全结合使用,这推动文件为基础的应用程序从"玩具"到"用于实际自动化工具的可行" -这个小众的Powershell和小型Python脚本多年来一直拥有。
.NET run -e FOO=BAR允许您在命令行上传递环境变量,无需导出shell状态或编辑启动配置。 很微小,但如果您曾经打开过三个终端,使用不同的ASPNETCORE_ENVIRONMENT值,您就知道这有多痛苦。
.NET watch与Aspire应用程序主机集成,在崩溃后在下一个文件更改时自动重新启动,并为WinForms和WPF更优雅地处理Ctrl+C(一个永久的痛苦)。 .NET format接受--framework用于多目标项目。 .NET test在MTP模式下支持--artifacts-path。 而.NET tool exec / dnx不再提示进行额外的批准,这对一次性工具运行是一个摩擦点。
痛点
平衡的评价归于粗糙的边缘,而且预览3有这些。
工具链故事很粗糙。 Visual Studio 2026在.NET 10发布六个月后仍在预览,并且微软托管的构建代理还没有稳定的VS 2026支持。 在.NET 10的SDK补丁版本更改要求MSBuild 18(VS 2026),这完全违反了微软推广的语义版本承诺。 任何在微软托管的代理上运行CI的人不得不将SDK 10.0.4干线固定或切换到预览构建图像。 如果您正在考虑将CI管道移至.NET 11的预览期,预计更多的相似 - 团队自己的承认,预览SDK在10.0.2和10.0.3中破坏了东西,然后稳定下来。
运行时异步仍然是选择加入。 即使没有预览功能的阻拦,您也必须切换runtime-async=on。 对新项目代码来说还好; 对于在NuGet上发布的库,您仍不能假设您的用户打开了开关,因此实际的好处在特性默认打开(不在.NET 11中)之前被延迟。
硬件要求提升。 最低x86/x64指令集要求上调。大多数团队不会注意到。有些会 - 并且如果在部署时不先进行审计,他们会发现。
STS,不是LTS。 .NET 11支持24个月。 .NET 10,当前的LTS,得到36个月支持。 对于缓慢升级周期的公司来说,.NET 10仍然是更保守的选择,采用.NET 11意味着2028年再次升级。采用STS的理由是功能; 对于反对的理由是日历。
预览就是预览。 这不是一个关于稳定性的抱怨 - 微软的预览过程一直做得不错 - 但预览3不是发布候选版本。 生产部署最早要等待RC1之发布。内部工具,副项目和探索目前是合适的范围。
判决
如果您每天都写C#,.NET 11预览3值得本周安装并尝试 - 特别是为了亲手体验联合类型,这是近年来最重要的语言变革。 如果您维护库,JIT和运行时异步的工作意味着您的代码将在.NET 11上更快,而无需编辑,这是最好的升级。 如果您发布MAUI应用程序,地图和手势的工作是真正的进步。
如果您运行生产.NET负载,答案是无聊的一个:继续计划,继续观察,并将GA标记在11月。 令人兴奋的部分已到来,但工具链 - VS,构建代理和SDK补丁节奏 - 是实际摩擦点,尚未解决。
| --- |
来源: .NET博客公告, .NET 11中的新功能 (Microsoft Learn), 运行时发行说明, ASP.NET Core发行说明, SDK发行说明, 探索C# 15中的联合类型。
