vlog
← 返回全部文章

Tech

社区手搓了六年的那个类型,C# 终于用一个关键字把它收进了语言里

2026年8月24日 · 保罗·格雷厄姆《黑客与画家》~1 min read

一行代码:public union Pet(Cat, Dog, Bird);。就这么长。为了凑出这一行的效果,C# 社区手工模拟了好些年,装个 OneOf 之类的第三方库,或者干脆拿 object 硬扛、处处防着。据社区与报道梳理,这个提案在 csharplang 仓库里从 2020 年前后就开始打转,语言设计会议在 2022、2024、2025 年各拿出来议过一轮。现在它随 C# 15 落地,在 .NET 11 Preview 2 里能摸到了。

30 秒读懂
1落地

一行声明,把「只能是这几个」交给编译器管

封闭,加上穷尽匹配。这两样就是这个关键字全部的分量。

写下 public union Pet(Cat, Dog, Bird); 之后,Pet 这个类型就只有这三种可能,第四种进不来。跟着来的是编译器强制穷尽匹配:你写 switch 漏掉一个 case,编译期就有人喊住你。你别看它表面只省了几行样板,真正换掉的是「漏了会怎样」归谁管:以前靠人记着,现在编译器替你算。

核心

union 声明的是封闭的类型集合,编译器强制穷尽匹配;它还能把毫不相干的类型并到一起,官方举的例子是 string 和 Exception。

⚡

为什么值得看:「一个值只能是这几种之一」这种事,你手上不管哪门语言,业务代码里都在写:结果要么成功要么失败,拿回来的要么是文本要么是异常。以前各家靠各家的土办法撑着,现在 C# 把它收进了关键字。

2凑合

三条老路,各缺一样东西

这三条是官方博客自己摆出来的。

老路缺的那一样
用 object 装没有类型安全,得处处写防御性代码
标记接口(marker interface,就是个空接口,只用来贴标签)不封闭,谁都能来继承一下
抽象基类同样不封闭,而且没法把互不相关的类型并起来

这三条里最像回事的是后两条。你定义一个空接口,让 Cat、Dog、Bird 都去实现它,看上去「一伙的」就圈好了。可这个圈没有门:随便谁在随便哪个程序集里再写一个类实现同一个接口,那个类也算这一伙的,你那个 switch 当天就少了一格,编译器一声不吭。

2013 年我在华南一家城商行做网银改造,那边所有变更走纸质签批,一式三份、六个章。4 月 17 日有一条配置,把某档利率的小数点挪了一位。六个章一个不落全盖齐了,照样上生产,回滚做到凌晨四点,行里食堂给加班的人煮了两锅面。那晚我想明白一件事:章管的是谁负责,不管对不对。空接口就是这种章,它记下了「我声称我跟他们是一伙的」,至于这伙人到底有几个、你有没有漏掉谁,它一栏都不管。

以前只能这么凑合

空接口把几个类圈成「一伙」,但圈上没门。谁在别处再实现一次,你的 switch 就少了一格,编译期什么都不会说。

现在

union 声明的集合是封闭的,成员就那几个;漏掉一个 case,编译期当场拦你。

3排队

2020 年前后立的案,排到 2026 年 11 月才发车

卡住它的从来不是写那个关键字。

时间发生了什么
2020 年前后「可辨别联合」的提案在 csharplang 仓库里开始打转
2022 / 2024 / 2025语言设计会议各议过一轮
2025 年 8 月C# 语言首席设计师 Mads Torgersen 在一段视频里讲了团队对 union 的打算,目标是随 2026 年 11 月的 C# 15 一起发布
眼下C# 15 在 .NET 11 Preview 1 开始出现,union 在 Preview 2 可用
上表时间线据社区与报道梳理,非官方原话;版本与可用范围以微软官方博客为准。

一个关键字要进语言,难的是跟屋里已经住着的东西挨个对账。集合一封闭,编译器就得替你算「有没有漏」,这笔账要跟模式匹配、可空引用类型、值类型与装箱这几户老住客一家家谈。谈成什么样,看官方自己列的限制清单最清楚,下一节全在里头。

语言这东西跟老楼加装电梯一个道理:电梯本身好买,难的是井道往哪儿开、谁家的窗户被挡上、水管电线怎么绕。

THREE WORKAROUNDS, EACH MISSING A DIFFERENT GUARANTEEBEFORE · WORKAROUNDSobject× type safetymarker interface / abstract base× closed setbase class× unrelated typesNOW · C# 15 · .NET 11 PREVIEW 2unionclosed set of typescompiler-enforced exhaustive matchpublic union Pet(Cat, Dog, Bird);LIMITS IN THIS PREVIEWvalue types get boxednullable needs a null armmember providers not implemented
Source: official blog, C# 15 · .NET 11 Preview 2 — each older workaround gives up a different guarantee; the union keyword supplies the closed set and the exhaustiveness check at once.
4没说完的

官方自己把这一版的欠账列出来了

欠账列得越具体,越说明它是真上路了。

官方列的限制落到手上是什么意思
值类型在 object? 的 Value 属性里会被装箱往 union 里放 int、struct 这类值类型,走这条路取值就有装箱开销
有 case 类型可空时,switch 表达式需要写 null 分支穷尽匹配这道闸会连 null 一起要求你交代
union member providers 尚未实现直接访问各 case 共有属性的能力,这个 preview 里还没有

装箱这条不算死路:官方给了个绕法,用 [Union] 特性自定义的 union,可以借 TryGetValue 实现不装箱的访问方式。绕得过去,前提是你自己知道要绕。

2007 年我入行,第一个活是给政务大厅做排队叫号系统。验收当天喇叭把「请 A052 号到 3 号窗口」念成了一串连读,全厅哄笑。需求方最后一条验收意见写的是「声音要像人」,我回去改了三天 TTS 停顿。功能那天全跑通了,验收表上一栏没缺,差的那三天在表外面。preview 里这份限制清单,占的就是那三天的位置。

上述限制均为官方博客在这一版列出的口径。preview 阶段的东西会动,后续版本以官方更新为准。
5路标

手搓了这些年的样板,本身就是设计图

保罗·格雷厄姆在《黑客与画家》里讲过这件事。

他的说法是「简洁就是力量」:语言之间真正的差别在表达力,同一件事,这门语言要你写一屏,那门语言三行说完。跟着还有更实用的一条:一门语言缺什么,程序员就会在它上面手工把那个东西模拟出来。缺的东西不会自己消失,只会变成样板代码,一遍一遍手抄。而这些反复出现的样板就是路标,指着这门语言下一步该长出什么。语言的进化,说白了就是把大家手搓了多年的模式,收进语言本身。

打个比方

厨房里拍蒜,几十年都是抄起菜刀,拿刀身侧面横过来按一下,人人这么干,谁也没觉得这是凑合。后来厂家把刀身加宽加厚,出了专门标着能拍蒜的那一款。厂家用不着去调研谁想要什么,看大家手上已经把什么当工具使,答案就摆在案板上。

OneOf 那类库,就是那把拿来拍蒜的菜刀。它能用,可它一直在提醒一件事:这门语言里缺着一格。

6落到你手上

这对你意味着什么

三件今天就能想清楚的事。

第一,preview 就是 preview。union 现在在 .NET 11 Preview 2 里,能摸能试,别急着往生产项目的核心数据模型上招呼。官方自己还有三条限制挂在那儿,其中 member providers 是干脆没实现。

第二,真要试,先量装箱那一头。值类型走 object? 的 Value 属性会被装箱,你的 union 里如果塞的是 int、struct 这类东西,又跑在热路径上,这笔开销得自己拿数据说话,别拿感觉说话。要绕就走 [Union] 特性加 TryGetValue 那条。

第三,不写 C# 的照做一遍:翻翻自己项目里反复复制粘贴的那几坨结构,看哪几坨是在替语言补一格缺口。你手抄了几年的那个模式,值不值得被收进语言、收进来那天会不会捎一串限制,是同一件事的两头。

这行 public union Pet(Cat, Dog, Bird); 现在写得出来了。至于它啥时候能让人闭着眼往生产上用,盯那三条限制什么时候划掉。

本文框架取材自保罗·格雷厄姆《黑客与画家》;union 的语法、能力与限制口径来自微软官方博客(devblogs.microsoft.com),提案时间线据社区与报道梳理,细节以官方博客为准。本文为技术解读,非工程建议;版本行为以你实际使用的版本为准。

技术

社区手搓了六年的那个类型,C# 终于用一个关键字把它收进了语言里

2026年8月24日 · 保罗·格雷厄姆《黑客与画家》约 6 分钟

一行代码:public union Pet(Cat, Dog, Bird);。就这么长。为了凑出这一行的效果,C# 社区手工模拟了好些年,装个 OneOf 之类的第三方库,或者干脆拿 object 硬扛、处处防着。据社区与报道梳理,这个提案在 csharplang 仓库里从 2020 年前后就开始打转,语言设计会议在 2022、2024、2025 年各拿出来议过一轮。现在它随 C# 15 落地,在 .NET 11 Preview 2 里能摸到了。

30 秒读懂
1落地

一行声明,把「只能是这几个」交给编译器管

封闭,加上穷尽匹配。这两样就是这个关键字全部的分量。

写下 public union Pet(Cat, Dog, Bird); 之后,Pet 这个类型就只有这三种可能,第四种进不来。跟着来的是编译器强制穷尽匹配:你写 switch 漏掉一个 case,编译期就有人喊住你。你别看它表面只省了几行样板,真正换掉的是「漏了会怎样」归谁管:以前靠人记着,现在编译器替你算。

核心

union 声明的是封闭的类型集合,编译器强制穷尽匹配;它还能把毫不相干的类型并到一起,官方举的例子是 string 和 Exception。

⚡

为什么值得看:「一个值只能是这几种之一」这种事,你手上不管哪门语言,业务代码里都在写:结果要么成功要么失败,拿回来的要么是文本要么是异常。以前各家靠各家的土办法撑着,现在 C# 把它收进了关键字。

2凑合

三条老路,各缺一样东西

这三条是官方博客自己摆出来的。

老路缺的那一样
用 object 装没有类型安全,得处处写防御性代码
标记接口(marker interface,就是个空接口,只用来贴标签)不封闭,谁都能来继承一下
抽象基类同样不封闭,而且没法把互不相关的类型并起来

这三条里最像回事的是后两条。你定义一个空接口,让 Cat、Dog、Bird 都去实现它,看上去「一伙的」就圈好了。可这个圈没有门:随便谁在随便哪个程序集里再写一个类实现同一个接口,那个类也算这一伙的,你那个 switch 当天就少了一格,编译器一声不吭。

2013 年我在华南一家城商行做网银改造,那边所有变更走纸质签批,一式三份、六个章。4 月 17 日有一条配置,把某档利率的小数点挪了一位。六个章一个不落全盖齐了,照样上生产,回滚做到凌晨四点,行里食堂给加班的人煮了两锅面。那晚我想明白一件事:章管的是谁负责,不管对不对。空接口就是这种章,它记下了「我声称我跟他们是一伙的」,至于这伙人到底有几个、你有没有漏掉谁,它一栏都不管。

以前只能这么凑合

空接口把几个类圈成「一伙」,但圈上没门。谁在别处再实现一次,你的 switch 就少了一格,编译期什么都不会说。

现在

union 声明的集合是封闭的,成员就那几个;漏掉一个 case,编译期当场拦你。

3排队

2020 年前后立的案,排到 2026 年 11 月才发车

卡住它的从来不是写那个关键字。

时间发生了什么
2020 年前后「可辨别联合」的提案在 csharplang 仓库里开始打转
2022 / 2024 / 2025语言设计会议各议过一轮
2025 年 8 月C# 语言首席设计师 Mads Torgersen 在一段视频里讲了团队对 union 的打算,目标是随 2026 年 11 月的 C# 15 一起发布
眼下C# 15 在 .NET 11 Preview 1 开始出现,union 在 Preview 2 可用
上表时间线据社区与报道梳理,非官方原话;版本与可用范围以微软官方博客为准。

一个关键字要进语言,难的是跟屋里已经住着的东西挨个对账。集合一封闭,编译器就得替你算「有没有漏」,这笔账要跟模式匹配、可空引用类型、值类型与装箱这几户老住客一家家谈。谈成什么样,看官方自己列的限制清单最清楚,下一节全在里头。

语言这东西跟老楼加装电梯一个道理:电梯本身好买,难的是井道往哪儿开、谁家的窗户被挡上、水管电线怎么绕。

三条老路,各缺一样保证此前的凑合办法object× 类型安全标记接口 / 抽象基类× 封闭集合基类× 互不相关的类型NOW · C# 15 · .NET 11 PREVIEW 2union封闭的类型集合编译器强制穷尽匹配public union Pet(Cat, Dog, Bird);本版限制值类型装箱可空需写 null 分支member providers 未实现
来源:官方博客,C# 15 · .NET 11 Preview 2。三条老路各缺一样保证,union 关键字把封闭集合与穷尽检查一次补齐。
4没说完的

官方自己把这一版的欠账列出来了

欠账列得越具体,越说明它是真上路了。

官方列的限制落到手上是什么意思
值类型在 object? 的 Value 属性里会被装箱往 union 里放 int、struct 这类值类型,走这条路取值就有装箱开销
有 case 类型可空时,switch 表达式需要写 null 分支穷尽匹配这道闸会连 null 一起要求你交代
union member providers 尚未实现直接访问各 case 共有属性的能力,这个 preview 里还没有

装箱这条不算死路:官方给了个绕法,用 [Union] 特性自定义的 union,可以借 TryGetValue 实现不装箱的访问方式。绕得过去,前提是你自己知道要绕。

2007 年我入行,第一个活是给政务大厅做排队叫号系统。验收当天喇叭把「请 A052 号到 3 号窗口」念成了一串连读,全厅哄笑。需求方最后一条验收意见写的是「声音要像人」,我回去改了三天 TTS 停顿。功能那天全跑通了,验收表上一栏没缺,差的那三天在表外面。preview 里这份限制清单,占的就是那三天的位置。

上述限制均为官方博客在这一版列出的口径。preview 阶段的东西会动,后续版本以官方更新为准。
5路标

手搓了这些年的样板,本身就是设计图

保罗·格雷厄姆在《黑客与画家》里讲过这件事。

他的说法是「简洁就是力量」:语言之间真正的差别在表达力,同一件事,这门语言要你写一屏,那门语言三行说完。跟着还有更实用的一条:一门语言缺什么,程序员就会在它上面手工把那个东西模拟出来。缺的东西不会自己消失,只会变成样板代码,一遍一遍手抄。而这些反复出现的样板就是路标,指着这门语言下一步该长出什么。语言的进化,说白了就是把大家手搓了多年的模式,收进语言本身。

打个比方

厨房里拍蒜,几十年都是抄起菜刀,拿刀身侧面横过来按一下,人人这么干,谁也没觉得这是凑合。后来厂家把刀身加宽加厚,出了专门标着能拍蒜的那一款。厂家用不着去调研谁想要什么,看大家手上已经把什么当工具使,答案就摆在案板上。

OneOf 那类库,就是那把拿来拍蒜的菜刀。它能用,可它一直在提醒一件事:这门语言里缺着一格。

6落到你手上

这对你意味着什么

三件今天就能想清楚的事。

第一,preview 就是 preview。union 现在在 .NET 11 Preview 2 里,能摸能试,别急着往生产项目的核心数据模型上招呼。官方自己还有三条限制挂在那儿,其中 member providers 是干脆没实现。

第二,真要试,先量装箱那一头。值类型走 object? 的 Value 属性会被装箱,你的 union 里如果塞的是 int、struct 这类东西,又跑在热路径上,这笔开销得自己拿数据说话,别拿感觉说话。要绕就走 [Union] 特性加 TryGetValue 那条。

第三,不写 C# 的照做一遍:翻翻自己项目里反复复制粘贴的那几坨结构,看哪几坨是在替语言补一格缺口。你手抄了几年的那个模式,值不值得被收进语言、收进来那天会不会捎一串限制,是同一件事的两头。

这行 public union Pet(Cat, Dog, Bird); 现在写得出来了。至于它啥时候能让人闭着眼往生产上用,盯那三条限制什么时候划掉。

本文框架取材自保罗·格雷厄姆《黑客与画家》;union 的语法、能力与限制口径来自微软官方博客(devblogs.microsoft.com),提案时间线据社区与报道梳理,细节以官方博客为准。本文为技术解读,非工程建议;版本行为以你实际使用的版本为准。

テクノロジー

社区手搓了六年的那个类型,C# 终于用一个关键字把它收进了语言里

2026年8月24日 · 保罗·格雷厄姆《黑客与画家》約 6 分

一行代码:public union Pet(Cat, Dog, Bird);。就这么长。为了凑出这一行的效果,C# 社区手工模拟了好些年,装个 OneOf 之类的第三方库,或者干脆拿 object 硬扛、处处防着。据社区与报道梳理,这个提案在 csharplang 仓库里从 2020 年前后就开始打转,语言设计会议在 2022、2024、2025 年各拿出来议过一轮。现在它随 C# 15 落地,在 .NET 11 Preview 2 里能摸到了。

30 秒读懂
1落地

一行声明,把「只能是这几个」交给编译器管

封闭,加上穷尽匹配。这两样就是这个关键字全部的分量。

写下 public union Pet(Cat, Dog, Bird); 之后,Pet 这个类型就只有这三种可能,第四种进不来。跟着来的是编译器强制穷尽匹配:你写 switch 漏掉一个 case,编译期就有人喊住你。你别看它表面只省了几行样板,真正换掉的是「漏了会怎样」归谁管:以前靠人记着,现在编译器替你算。

核心

union 声明的是封闭的类型集合,编译器强制穷尽匹配;它还能把毫不相干的类型并到一起,官方举的例子是 string 和 Exception。

⚡

为什么值得看:「一个值只能是这几种之一」这种事,你手上不管哪门语言,业务代码里都在写:结果要么成功要么失败,拿回来的要么是文本要么是异常。以前各家靠各家的土办法撑着,现在 C# 把它收进了关键字。

2凑合

三条老路,各缺一样东西

这三条是官方博客自己摆出来的。

老路缺的那一样
用 object 装没有类型安全,得处处写防御性代码
标记接口(marker interface,就是个空接口,只用来贴标签)不封闭,谁都能来继承一下
抽象基类同样不封闭,而且没法把互不相关的类型并起来

这三条里最像回事的是后两条。你定义一个空接口,让 Cat、Dog、Bird 都去实现它,看上去「一伙的」就圈好了。可这个圈没有门:随便谁在随便哪个程序集里再写一个类实现同一个接口,那个类也算这一伙的,你那个 switch 当天就少了一格,编译器一声不吭。

2013 年我在华南一家城商行做网银改造,那边所有变更走纸质签批,一式三份、六个章。4 月 17 日有一条配置,把某档利率的小数点挪了一位。六个章一个不落全盖齐了,照样上生产,回滚做到凌晨四点,行里食堂给加班的人煮了两锅面。那晚我想明白一件事:章管的是谁负责,不管对不对。空接口就是这种章,它记下了「我声称我跟他们是一伙的」,至于这伙人到底有几个、你有没有漏掉谁,它一栏都不管。

以前只能这么凑合

空接口把几个类圈成「一伙」,但圈上没门。谁在别处再实现一次,你的 switch 就少了一格,编译期什么都不会说。

现在

union 声明的集合是封闭的,成员就那几个;漏掉一个 case,编译期当场拦你。

3排队

2020 年前后立的案,排到 2026 年 11 月才发车

卡住它的从来不是写那个关键字。

时间发生了什么
2020 年前后「可辨别联合」的提案在 csharplang 仓库里开始打转
2022 / 2024 / 2025语言设计会议各议过一轮
2025 年 8 月C# 语言首席设计师 Mads Torgersen 在一段视频里讲了团队对 union 的打算,目标是随 2026 年 11 月的 C# 15 一起发布
眼下C# 15 在 .NET 11 Preview 1 开始出现,union 在 Preview 2 可用
上表时间线据社区与报道梳理,非官方原话;版本与可用范围以微软官方博客为准。

一个关键字要进语言,难的是跟屋里已经住着的东西挨个对账。集合一封闭,编译器就得替你算「有没有漏」,这笔账要跟模式匹配、可空引用类型、值类型与装箱这几户老住客一家家谈。谈成什么样,看官方自己列的限制清单最清楚,下一节全在里头。

语言这东西跟老楼加装电梯一个道理:电梯本身好买,难的是井道往哪儿开、谁家的窗户被挡上、水管电线怎么绕。

欠ける保証が別々代替策object× 型安全marker interface / 抽象基底× 閉じた集合基底クラス× 無関係な型NOW · C# 15 · .NET 11 PREVIEW 2union閉じた集合網羅を強制public union Pet(Cat, Dog, Bird);制限値型は boxingnull 分岐必須member providers 未実装
出典は公式ブログに準じる。欠けた保証を union が補う。
4没说完的

官方自己把这一版的欠账列出来了

欠账列得越具体,越说明它是真上路了。

官方列的限制落到手上是什么意思
值类型在 object? 的 Value 属性里会被装箱往 union 里放 int、struct 这类值类型,走这条路取值就有装箱开销
有 case 类型可空时,switch 表达式需要写 null 分支穷尽匹配这道闸会连 null 一起要求你交代
union member providers 尚未实现直接访问各 case 共有属性的能力,这个 preview 里还没有

装箱这条不算死路:官方给了个绕法,用 [Union] 特性自定义的 union,可以借 TryGetValue 实现不装箱的访问方式。绕得过去,前提是你自己知道要绕。

2007 年我入行,第一个活是给政务大厅做排队叫号系统。验收当天喇叭把「请 A052 号到 3 号窗口」念成了一串连读,全厅哄笑。需求方最后一条验收意见写的是「声音要像人」,我回去改了三天 TTS 停顿。功能那天全跑通了,验收表上一栏没缺,差的那三天在表外面。preview 里这份限制清单,占的就是那三天的位置。

上述限制均为官方博客在这一版列出的口径。preview 阶段的东西会动,后续版本以官方更新为准。
5路标

手搓了这些年的样板,本身就是设计图

保罗·格雷厄姆在《黑客与画家》里讲过这件事。

他的说法是「简洁就是力量」:语言之间真正的差别在表达力,同一件事,这门语言要你写一屏,那门语言三行说完。跟着还有更实用的一条:一门语言缺什么,程序员就会在它上面手工把那个东西模拟出来。缺的东西不会自己消失,只会变成样板代码,一遍一遍手抄。而这些反复出现的样板就是路标,指着这门语言下一步该长出什么。语言的进化,说白了就是把大家手搓了多年的模式,收进语言本身。

打个比方

厨房里拍蒜,几十年都是抄起菜刀,拿刀身侧面横过来按一下,人人这么干,谁也没觉得这是凑合。后来厂家把刀身加宽加厚,出了专门标着能拍蒜的那一款。厂家用不着去调研谁想要什么,看大家手上已经把什么当工具使,答案就摆在案板上。

OneOf 那类库,就是那把拿来拍蒜的菜刀。它能用,可它一直在提醒一件事:这门语言里缺着一格。

6落到你手上

这对你意味着什么

三件今天就能想清楚的事。

第一,preview 就是 preview。union 现在在 .NET 11 Preview 2 里,能摸能试,别急着往生产项目的核心数据模型上招呼。官方自己还有三条限制挂在那儿,其中 member providers 是干脆没实现。

第二,真要试,先量装箱那一头。值类型走 object? 的 Value 属性会被装箱,你的 union 里如果塞的是 int、struct 这类东西,又跑在热路径上,这笔开销得自己拿数据说话,别拿感觉说话。要绕就走 [Union] 特性加 TryGetValue 那条。

第三,不写 C# 的照做一遍:翻翻自己项目里反复复制粘贴的那几坨结构,看哪几坨是在替语言补一格缺口。你手抄了几年的那个模式,值不值得被收进语言、收进来那天会不会捎一串限制,是同一件事的两头。

这行 public union Pet(Cat, Dog, Bird); 现在写得出来了。至于它啥时候能让人闭着眼往生产上用,盯那三条限制什么时候划掉。

本文框架取材自保罗·格雷厄姆《黑客与画家》;union 的语法、能力与限制口径来自微软官方博客(devblogs.microsoft.com),提案时间线据社区与报道梳理,细节以官方博客为准。本文为技术解读,非工程建议;版本行为以你实际使用的版本为准。