当前位置: 首页 > news >正文

C# 终于支持 union types 了

C# 15 中的联合 unionIntrounion联合类型在 C# 中的需求一直很高现在终于要来了。从 .NET 11 Preview 2 开始C# 15 引入了 union 关键字。union 关键字声明一个值恰好是固定类型集合中的一种并且具有编译器强制执行的穷尽模式匹配。C# 的联合旨在提供原生的 C# 使用体验它们是组合现有类型的类型联合与模式匹配集成并与语言的其余部分无缝协作。Whatunion可以是几个不同类型的组合换句话说一个值只能是几种指定类型中的其中一种。--- 有穷尽的类型枚举联合体是一组相互关联的特性它们共同为 C# 提供对联合体类型的支持• 联合体类型带有[Union]特性的结构体和类会被识别为联合体类型并支持联合体行为。• 案例类型联合类型具有一组案例类型表示其内容值可以具有的类型。• 联合体行为联合体类型支持以下联合体行为• 联合体转换每个类型都存在到联合体的隐式转换。• 联合体匹配对联合体值进行模式匹配时会隐式地“解包”其内容并将模式应用于底层值Value。• 联合体穷尽性当所有类型都匹配完毕时对联合体值执行 switch 表达式是穷尽的无需回退类型。• 联合体可空性可空性分析增强了对联合体内容空状态的跟踪。• 联合体模式所有联合体类型都遵循一个基本的联合体模式但还有一些可选模式用于特定场景。• 联合体声明可以使用简写语法直接声明联合体类型。该实现方式是“预设的”——结构体声明遵循基本的联合模式并将内容存储为单个引用字段。在 .NET Preview 4 之前要使用的话还需要声明以下 polyfill 代码在 .NET 11 Preview 4 之后就不需要自己声明了已经包含在框架类库中了 https://github.com/dotnet/runtime/pull/127001namespace System.Runtime.CompilerServices; [AttributeUsage(Class | Struct, AllowMultiple false, Inherited false)] public sealed class UnionAttribute : Attribute; public interface IUnion { object? Value { get; } }SamplesGet Started举个例子public record class Cat(string Name); public record class Dog(string Name); public union Pet(Cat, Dog);这里定义了Cat和Dog两个类型然后定义了一个union这个union由Cat和Dog组成这个Petunion 就可以是Dog也可以是Cat不可以是其他的类型使用示例如下Pet pet new Cat(A); Console.WriteLine(pet switch { Cat c $Cat: {c.Name}, Dog d $Dog: {d.Name} });这里我们不需要指定_fallback 匹配因为Pet只会出现Cat/Dog这两种类型编译器也不会给出警告如果未来 Pet 新增了其他类型编译器就会给出警告The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern Xxx is not covered.union的声明会自动创建隐式转换像前面的Pet pet new Cat(A);一样编译器可以自动完成从具体类型到联合类型的隐式转换联合还比较适合用于 Result 模式示例如下public union GetUserResult(User, NotFoundError, ValidationError); return result switch { User u Ok(u), NotFoundError e NotFound(e.Message), ValidationError e BadRequest(e.Message), };反编译看一下代码Pet decompilation可以看到 union 默认是生成了一个struct并且添加了 Union Attribute 并实现了IUnion接口通过Value返回其中的对象这里可以看到如果是值类型的话就会发生装箱这对于一些对于热路径性能敏感的代码处使用默认的实现可能会存在性能问题我们也可以有自己的实现来避免发生装箱public union IntegerOrString(int, string); IntegerOrString union1 42; IntegerOrString union2 Hello; Console.WriteLine($Union1: {union1.Value}); Console.WriteLine($Union2: {union2.Value});IntegerOrStringAvoid Boxing在默认的实现中对于值类型来说会出现装箱的问题如上面的示例所示对比 union 也支持了另外一个模式来避免装箱// Non-boxing access members public bool HasValue { get { ... } } public bool TryGetValue(out Dog value) { ... }• 如果 Union 的Value不是null,HasValue应该返回true•TryGetValue仅在联合的值是给定案例类型的非空值时返回true并且如果是这样则将该值传递到方法的out参数中。避免装箱的一个示例如下[Union] public readonly struct IntegerOrStringCustomized { private readonly string? _value; private readonly int? _num null; public IntegerOrStringCustomized(int num) { _num num; } public IntegerOrStringCustomized(string value) { _value value; } public object? Value _num is null ? _value : ${_num}; public bool HasValue _value is not null _num is not null; public bool TryGetValue(out int? value) { if (_num is int intNum) { value intNum; return true; } value null; return false; } public bool TryGetValue(out string? value) { if (_value is string stringValue) { value stringValue; return true; } value null; return false; } }使用示例如下IntegerOrStringCustomized union3 42; if (union3.TryGetValue(out int? num)) { Console.WriteLine($Union3 integer value is {num}); } union3 Hello; if (union3.TryGetValue(out string? str)) { Console.WriteLine($Union3 string value is {str}); }这里的UnionAttribute 是必须的否则不会被当作 union 不能进行隐式转换会得到下面的错误// CS0029: Cannot implicitly convert type int to CSharp15Samples.IntegerOrStringCustomized另外如果要支持 switch 模式匹配的话必须要有一个公开的object? Value { get; }属性不然编译器会报错// Missing compiler required member IntegerOrStringCustomized.Value使用如下var stringValue union3 switch { int i i.ToString(), string s s }; Console.WriteLine(stringValue);反编译看一下实现会是什么样的More目前 union 还在不断的完善包括 union 本身的优化如IUnionMembers等以及框架的支持比如 JSON 序列化和 ASP.NET Core 的支持期待越来越完善好用。References• https://github.com/dotnet/csharplang/blob/main/proposals/unions.md• https://andrewlock.net/exploring-the-dotnet-11-preview-2-dotnet-gets-union-types• https://github.com/dotnet/runtime/pull/127001• https://github.com/WeihanLi/SamplesInPractice/blob/main/Net11Samples/CSharp15Samples/UnionSample.cs
http://www.zskr.cn/news/1409968.html

相关文章:

  • .NET + 消息队列:稳稳扛住百亿流水,这才是企业级架构的真正底气
  • 从‘退化因子’到‘健康指标’:给你的机器人状态估计做个‘体检’
  • Python 入门:初识函数
  • 别再傻傻分不清!一文搞懂CPU、GPU、NPU、MCU、DSP、FPGA、SOC,嵌入式选型不踩坑
  • 侈品级不锈钢彩色板应用技术标准:从选材、工艺到验收的完整规范
  • DevOps CI/CD流水线最佳实践:从Git提交到生产部署的10分钟之旅
  • LVDS串行通信总线深度分析
  • 灰子学Ai: Token与字节
  • AI品牌命名避坑清单(含12个高危词根、6类语音陷阱、4种文化禁忌),错过本次更新将影响全球市场准入
  • SARscape版本升级实战:5.3到5.6.2,那些官方没细说的数据导入与DEM处理变化
  • 别再怕走廊和隧道了!用LOAM作者的方法搞定SLAM定位退化问题
  • 数据分析入门:手把手教你用Python爬取直播数据并做简单可视化
  • 开源语音AI的边界:从 `luongnv89/claude-howto` 看前沿技术的落地实践
  • 别再死记硬背公式了!用这个在线仿真工具,5分钟搞懂正激变换器(Forward Converter)工作原理
  • 2026指南:东莞老化房专业品牌厂家甄选 - 品牌企业推荐师(官方)
  • 算法:图的存储与遍历,最小生成树(Prim算法,kruskal算法)
  • 高光谱图像超分辨率技术:Mamba架构与实时处理实践
  • 别再只画轮廓了!用OpenCV的cv2.findContours()做点实际的:Python实现简易车牌识别
  • 别再破坏原车线束了!手把手教你用120通道BOB故障测试盒做汽车ECU信号诊断
  • 从野外数据到地下构造:手把手教你用地震时距曲线做一次‘虚拟勘探’
  • 别再死记硬背了!用“数据流”视角彻底理解F28335的SCI模块:从SCITXBUF到TXSHF发生了什么?
  • 告别ST-LINK!详解STM32G070RB开发板的串口一键下载配置与常见连接失败解决
  • 别再死记硬背了!用WideDeep模型搞定推荐系统里的‘记忆’与‘泛化’难题
  • Python 新手入门,用 AI 写个自动诗歌生成器
  • 保姆级教程:在Win10上用VMware 15.5.2给Mac OS X 10.11安个家(附解锁工具和镜像)
  • 别再只用SSH了!在Ubuntu 20.04上快速启用Telnet服务,搞定那些老旧设备的远程调试
  • 5分钟掌握chfsgui:零门槛文件共享神器新手必看指南
  • 三分钟解锁B站4K视频下载:告别在线播放限制的智能解决方案
  • 网卡代理商选型参考:三层漏斗筛选核心维度一次说清
  • 从Vue项目实战出发:一步步教你用Echarts 5.3.3 + china.js绘制可交互的中国地图(附完整代码)