弃元是c# 7.0引入的语法特性,用下划线“_”表示不使用的值,编译器识别后跳过分配与引用,不占内存、不触发未使用警告,仅在特定上下文(如解构、out、模式匹配)中生效。

什么是 C# 中的弃元(discard)
弃元是 C# 7.0 引入的语法特性,用单个下划线 _ 表示一个“不打算使用的变量”。它不是关键字,而是一个特殊标识符,编译器会识别并跳过对其的分配和后续引用。它不占用内存,也不参与作用域检查——本质上,_ 告诉编译器:“这个值我明确不要,别报错,也别管它。”
什么时候必须用 _ 而不是随便起个变量名
常见于解构、模式匹配、out 参数、事件订阅等场景,当语言要求你提供变量名但你又不需要该值时,用普通变量名(比如 temp 或 unused)会触发 IDE 警告(CS0219:变量已赋值但从未使用),而弃元可彻底消除这类警告和冗余。
- 解构元组时忽略部分元素:
(int x, _) = (1, 2); - 调用带
out参数的方法且只关心返回值:int.TryParse("42", out _); - 匹配
switch表达式中不关心的具体值:shape switch { Circle _ => "circular", _ => "other" }; - 事件处理中忽略 sender 和 e:
button.Click += (_, _) => Console.WriteLine("clicked");
_ 不是万能的:不能重复声明或用于 ref/out 以外的上下文
弃元不是变量,所以不能在同一个作用域里多次出现独立的 _ 作为左值(C# 9 开始允许在某些场景下“重用”,但仍有严格限制)。更重要的是,它不能用于需要实际变量引用的地方:
- 不能写
ref int r = ref _;—— 报错 CS8171:“无法对弃元使用 ref” - 不能在
foreach中写foreach (var _ in list)—— 编译失败,必须用有效标识符 - 不能在属性初始化器或字段声明中使用
_作为占位符(如private int _ = 0;是合法的,但这不是弃元,而是普通字段名) - 多个弃元在同一个表达式中是允许的,但语义上它们彼此无关,比如
(_, _, var z) = GetTriple();
与旧写法对比:为什么弃元比 unused 更安全
过去常用 var unused = ...; 或 int dummy; 来“吃掉”无用值,但这会带来真实变量开销、可能意外被读取、IDE 提示干扰,甚至引发静态分析工具误报。弃元从语法层面切断了所有误用路径:
-
_在任何位置被读取都会编译错误(CS0103:“名称‘_’不存在于当前上下文中”) - 它不会出现在调试器变量窗口中,也不会出现在反编译后的 IL 中
- 在模式匹配中,
_是唯一能表示“匹配任意值且不绑定”的符号;写var x会绑定,写var _是非法的 - 注意:C# 7.0–8.0 中,
_只能在特定上下文(如out、解构、is模式)中作为弃元;C# 9+ 才支持更通用的“目标类型弃元”,比如_ = SomeMethod();
真正容易被忽略的是弃元的“上下文敏感性”:它只有在编译器明确支持弃元的语法位置才生效;在其他地方敲下 _,它就是个普通(但不推荐的)变量名,既不省事,也不安全。










