0

0

C#的discard模式怎么忽略不需要的值?适用场景是什么?

幻夢星雲

幻夢星雲

发布时间:2025-08-30 08:37:01

|

696人浏览过

|

来源于php中文网

原创

C#的discard模式通过下划线_明确忽略无需使用的值,提升代码清晰度与可维护性。它适用于忽略方法返回值、out参数、元组解构中的元素、模式匹配及lambda参数等场景。在元组解构中,用(var, _, _)替代无意义的占位变量名,消除编译器警告并增强可读性;在模式匹配中,_可匹配任意值而不捕获,使条件逻辑更简洁。相比声明未使用变量,discard更准确表达“不关心”语义,避免误导与警告堆积。但在调试时可能隐藏关键信息,且需警惕过度使用导致未来扩展困难。因此,应仅在确定值无后续用途时使用,确保语义准确。

c#的discard模式怎么忽略不需要的值?适用场景是什么?

C#的discard模式,说白了,就是用一个下划线

_
来明确告诉编译器和读代码的人:“这个值我不需要,请直接忽略掉。”它的适用场景非常广泛,只要你遇到一个方法或表达式会产生一个你当下不关心的结果,就可以考虑用它来简化代码,提升意图的清晰度。

解决方案

在C#中,

_
作为discard(废弃)标识符,可以用来忽略各种不需要的值。这不仅仅是避免“未使用变量”警告那么简单,它更是一种语义上的声明,让代码意图更明确。

最常见的应用场景包括:

  1. 忽略方法或属性的返回值: 有时候一个方法会返回一个值,但你并不需要它。

    void DoSomethingAndReturnStatus() { /* ... */ }
    // 如果你只关心副作用,不关心返回值
    _ = DoSomethingAndReturnStatus();

    这里

    _
    作为一个独立的表达式,接收了返回值但立即丢弃。

  2. 忽略

    out
    参数: 当一个方法有多个
    out
    参数,但你只对其中一部分感兴趣时。

    bool TryParse(string s, out int result);
    
    if (int.TryParse("123", out _)) // 只需要知道是否成功,不关心解析出的具体值
    {
        Console.WriteLine("解析成功!");
    }
    
    // 或者,如果你只关心部分out参数
    void GetUserInfo(int id, out string name, out int age, out string email);
    GetUserInfo(1, out string userName, out _, out _); // 只需要名字
  3. 忽略元组(Tuple)或自定义类型解构(Deconstruction)中的元素: 当一个方法返回一个元组,或者你对一个对象进行解构,但只需要其中的部分数据时。

    (string name, int age, string city) GetPersonInfo() => ("张三", 30, "北京");
    
    var (personName, _, _) = GetPersonInfo(); // 只需要名字,忽略年龄和城市
    Console.WriteLine($"姓名: {personName}");
    
    // 对于自定义类型,如果你定义了Deconstruct方法:
    public class Point
    {
        public int X { get; }
        public int Y { get; }
        public Point(int x, int y) { X = x; Y = y; }
        public void Deconstruct(out int x, out int y) { x = X; y = Y; }
    }
    Point p = new Point(10, 20);
    var (x, _) = p; // 只关心X坐标
    Console.WriteLine($"X坐标: {x}");
  4. 在模式匹配中忽略值: C# 7.0及更高版本引入的模式匹配功能,

    _
    在这里扮演了“匹配任何值但不需要捕获”的角色。

    object obj = "hello";
    
    if (obj is string _) // 匹配任何字符串类型,但不需要把字符串值存起来
    {
        Console.WriteLine("这是一个字符串。");
    }
    
    // 在switch表达式或switch语句中
    string GetTypeDescription(object o) => o switch
    {
        int i => $"整数: {i}",
        string s => $"字符串: {s}",
        _ => "未知类型" // 匹配任何其他类型,不关心具体值
    };
    Console.WriteLine(GetTypeDescription(123));
    Console.WriteLine(GetTypeDescription(true));
  5. 忽略lambda表达式的参数: 虽然不常见,但如果你需要一个lambda表达式,但某个参数在逻辑中没有被用到,也可以用

    _

    Func<int, int, int> add = (x, _) => x + 10; // 忽略第二个参数
    Console.WriteLine(add(5, 100)); // 输出 15

C# Discard模式在元组解构中如何提升代码可读性

我个人觉得,Discard模式在元组解构中对代码可读性的提升是显而易见的。在没有Discard模式之前,如果一个元组有三个元素,你只想要第一个,你可能得写成这样:

(string name, string dummyAge, string dummyCity) = GetPersonInfo();
// 或者更糟,直接忽略后面两个变量,但编译器会警告“未使用变量”
// var (name, age, city) = GetPersonInfo(); // 然后age和city被忽略

这两种方式都有问题。第一种,

dummyAge
dummyCity
这样的命名,虽然解决了编译器的警告,但它们本身并没有实际意义,反而增加了代码的“噪音”,让读者误以为这些变量可能在其他地方被使用。说实话,这挺烦人的,写代码的时候还得想个“无用”的名字。

而有了Discard模式,代码就变得干净利落多了:

var (personName, _, _) = GetPersonInfo();
Console.WriteLine($"我们只关心名字:{personName}");

这里的

_
明确地向阅读者传达了一个信息:元组的第二个和第三个元素确实存在,但我们当前的代码逻辑就是不需要它们。这种显式的“不关心”比隐式的“未使用”要清晰得多。它消除了歧义,让代码的意图一目了然,避免了不必要的心理负担和可能的误解。在我看来,这不仅是语法糖,更是代码语义表达能力的一次提升。

何时应优先考虑使用Discard而不是声明一个未使用的变量?

在我看来,只要你明确知道某个值在当前上下文是多余的,就应该毫不犹豫地使用Discard,而不是声明一个未使用的变量。这背后有几个很实际的考量:

首先,意图的清晰性是最大的优势。声明一个

dummyVar
或者干脆不使用一个变量(然后面对编译器警告),都会给代码的读者带来困惑。他们可能会想:“这个变量为什么在这里?它有什么用?是不是我漏掉了什么逻辑?”而
_
则斩钉截铁地告诉他们:“别看了,这里真的没用。”这种明确的信号可以大大减少未来维护者的认知负担。

其次,避免编译器警告。C#编译器对未使用的变量通常会发出警告(CS0219),虽然这些警告不影响程序运行,但在大型项目中,积累过多的警告会掩盖真正的潜在问题,降低警告的有效性。使用Discard可以优雅地解决这个问题,让你的警告列表保持清爽,只显示真正需要关注的问题。

再者,从资源管理的角度来看,虽然现代编译器和运行时通常能优化掉未使用的局部变量,使其不占用实际内存,但

_
在某些情况下(比如作为
out
参数)可以确保不会有任何不必要的变量声明。这更多是一种代码风格和最佳实践的体现,强调了“不为不需要的东西分配任何资源”的原则。

举个例子,假设你有一个解析器方法,它会返回一个布尔值表示是否成功,并通过

out
参数返回解析结果。如果你只关心是否成功:

Tago AI
Tago AI

AI生成带货视频,专为电商卖货而生

下载
// 不推荐:声明一个不用的变量
// int result;
// if (int.TryParse("abc", out result)) { /* ... */ }

// 推荐:使用Discard
if (int.TryParse("abc", out _))
{
    Console.WriteLine("尝试解析成功,但结果不重要。");
}

这里,

out _
清晰地表达了“我只关心TryParse的返回值,不关心它解析出的具体整数值”。这比声明一个
result
变量然后不使用它要好得多,也比声明一个
dummyResult
变量来避免警告要优雅得多。在我日常开发中,只要遇到这种场景,我都会毫不犹豫地用
_

Discard模式在C# 9.0及更高版本的模式匹配中有哪些高级应用?

C# 9.0及更高版本,随着模式匹配能力的增强,Discard模式的应用场景也变得更加强大和灵活。它不再仅仅是“忽略一个值”,而是变成了“匹配任何值但不需要捕获它”的强大工具,尤其是在处理复杂的数据结构时,能让你的代码逻辑变得非常清晰。

我个人觉得,最让我眼前一亮的是它在属性模式 (Property Patterns)位置模式 (Positional Patterns) 中的应用。

1. 属性模式中的Discard: 当你想匹配一个对象的某个属性,但对其他属性不感兴趣时,Discard就能派上用场。 假设我们有一个

Order
类:

public class Order
{
    public int OrderId { get; set; }
    public decimal TotalAmount { get; set; }
    public string Status { get; set; }
}

Order myOrder = new Order { OrderId = 101, TotalAmount = 150.75m, Status = "Pending" };

// 传统方式:
if (myOrder != null && myOrder.Status == "Pending")
{
    // ...
}

// 使用属性模式和Discard:
if (myOrder is { Status: "Pending", TotalAmount: _ }) // 匹配状态为"Pending"的订单,但对总金额不感兴趣
{
    Console.WriteLine("这是一个待处理订单,总金额是多少不重要。");
}

// 更复杂的场景,比如只要状态是"Completed"且OrderId是任何值:
if (myOrder is { Status: "Completed", OrderId: _ })
{
    Console.WriteLine("订单已完成,订单ID不重要。");
}

这里,

TotalAmount: _
OrderId: _
明确表示我们匹配了这些属性的存在,但它们的具体值不影响我们的判断逻辑,也不需要把它们提取出来。这让条件判断变得非常简洁和富有表现力。

2. 位置模式中的Discard: 如果你有一个自定义类型,它定义了

Deconstruct
方法,或者是一个元组,你可以用位置模式来匹配其内部结构。Discard在这里可以忽略你不需要的特定位置的元素。

// 假设Point类定义了Deconstruct方法
Point p = new Point(10, 20);

// 匹配X坐标大于0的Point对象,忽略Y坐标
if (p is (> 0, _))
{
    Console.WriteLine("Point的X坐标大于0。");
}

// 对于元组也一样:
(string name, int age, string city) person = ("李四", 25, "上海");

// 匹配年龄在18到30之间的人,不关心姓名和城市
if (person is (_, >= 18 and <= 30, _))
{
    Console.WriteLine("这是一个年轻人。");
}

这种写法非常强大,它允许你像解构一样去“拆解”一个对象或元组,然后只关注你感兴趣的部分,而对不关心的部分直接用

_
忽略掉。这比写一堆嵌套的
if
条件判断要清晰和优雅得多。在我看来,Discard模式在模式匹配中的应用,真正体现了它作为一种“结构性忽略”工具的价值,极大地提升了复杂条件判断的可读性和简洁性。

Discard模式可能带来的误解或潜在陷阱是什么?

尽管Discard模式非常有用,但它也并非没有可能导致误解或潜在的陷阱。作为一个写代码的人,我个人觉得,在使用它的时候,还是需要多留个心眼。

一个最常见的“陷阱”是过度使用或误用。有时候,一个值虽然当前没有被直接使用,但在未来的某个重构或调试场景下,它可能变得至关重要。如果你习惯性地把所有暂时不用的值都Discard掉,那么当需要调试或者扩展功能时,你可能会发现你需要重新捕获这些值,这反而增加了工作量。我见过有同事在一些复杂的计算结果中,明明某个中间值可能对理解整个流程很有帮助,但为了“干净”而直接Discard,结果在排查问题时又不得不把Discard去掉,重新查看。所以,我觉得,用

_
的前提是,你非常确定这个值在任何可预见的未来都不会被用到,或者它的作用只是一个简单的“副作用触发器”。

另一个需要注意的点是调试时的可见性问题。被Discard的值在调试器中是不可见的,你无法在运行时检查它的具体内容。这在排查一些难以复现的bug时,可能会让你失去一个重要的信息来源。如果你怀疑某个被Discard的值可能与bug有关,那么在调试阶段,暂时移除

_
并将其赋值给一个临时变量,可能是个更好的选择。

再者,Discard模式在某些情况下可能会与变量声明产生视觉上的混淆。比如,在早期的C#版本中,

_
可以作为合法的变量名(虽然不推荐)。但在C# 7.0之后,
_
被赋予了Discard的特殊含义。这意味着,如果你在旧代码中遇到一个名为
_
的变量,它可能是一个真正的变量,而不是一个Discard。虽然现在编译器会强制区分,但在阅读混合了旧代码和新语法的项目时,这种上下文的切换还是需要一点适应的。

最后,就是语义上的细微差别

_
作为Discard,它表示的是“我不在乎这个值”。但这与简单地声明一个变量而不使用它(让编译器发出警告)还是有区别的。编译器对
_
的处理是“这个值确实存在,但你明确表示不想要它”,而对于未使用的变量,编译器会认为“你声明了一个变量,但忘了用它”,这两种意图是不同的。所以,确保你的“不关心”是真正的“不关心”,而不是“暂时没用到”或“忘了用”,这是关键。

总的来说,Discard模式是一个强大的工具,它能让代码更简洁、意图更明确。但就像任何强大的工具一样,它也需要被审慎地使用,理解它的边界和潜在的副作用,才能真正发挥它的价值。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

847

2023.08.22

mysql标识符无效错误怎么解决
mysql标识符无效错误怎么解决

mysql标识符无效错误的解决办法:1、检查标识符是否被其他表或数据库使用;2、检查标识符是否包含特殊字符;3、使用引号包裹标识符;4、使用反引号包裹标识符;5、检查MySQL的配置文件等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

210

2023.12.04

Python标识符有哪些
Python标识符有哪些

Python标识符有变量标识符、函数标识符、类标识符、模块标识符、下划线开头的标识符、双下划线开头、双下划线结尾的标识符、整型标识符、浮点型标识符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

323

2024.02.23

java标识符合集
java标识符合集

本专题整合了java标识符相关内容,想了解更多详细内容,请阅读下面的文章。

293

2025.06.11

c++标识符介绍
c++标识符介绍

本专题整合了c++标识符相关内容,阅读专题下面的文章了解更多详细内容。

178

2025.08.07

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

215

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

192

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

61

2026.01.05

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

37

2026.03.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 6万人学习

ASP 教程
ASP 教程

共34课时 | 5.9万人学习

Vue3.x 工具篇--十天技能课堂
Vue3.x 工具篇--十天技能课堂

共26课时 | 1.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号