弃元和弃元模式

Tip

本文是已了解至少一种编程语言并正在学习 C# 的开发人员的 “基础知识 ”部分的一部分。 如果你不熟悉模式,请从 模式匹配概述开始。 有关完整语法,请参阅 放弃模式引用

下划线标记(_)表示不需要某个值。 其确切含义取决于其显示位置:

上下文 _ 的含义
开关表达式臂或嵌套模式 匹配时不捕获结果的弃元模式
解构或 out 参数 忽略一个已生成值的丢弃操作
例如 _ = expression 这样的分配 计算表达式并忽略其结果的弃元赋值
两个或多个名为 _ 的 lambda 参数 弃用未使用输入内容的参数
var _ 在图案中 带弃元指定的 var 模式

这些表单共享拼写和意向,但它们不可互换。

利用 switch 的模式匹配

在下面的示例中, statusCode 是一个 int。 每个开关臂生成一 string 条消息,程序将写入控制台。 最后一个_处理除404200之外的所有状态代码:

static void ShowStatus()
{
    int statusCode = 503;
    string message = statusCode switch
    {
        200 => "Ready",
        404 => "Not found",
        _ => "Another status"
    };

    Console.WriteLine(message);
}

弃元模式应用于输入表达式。 C# 对表达式求值,而 _ 与求得的值匹配,但不对其进行捕获。 当所有前面未处理到的值都应使用相同的后备处理时,请选择 _ 作为 switch 表达式的最后一个分支。 把它放在最后,因为它会匹配所有内容,包括 null

形式 var _ 是一种带有 var 弃元指示符的模式。 它还匹配每个计算值,但它不会引入可读变量。 对于 switch 兜底分支,优先使用较短的 _ 弃元模式。 有关模式和指定的详细信息 var ,请参阅 声明、常量和 var 模式

解构声明

GetForecast返回一个元组,其中包含四个组成部分:一个城市和三intstring值,用于高温、低温和雨量。 解构声明会保留 cityhigh,因为程序会显示它们。 它使用 _ 来表示低温和降雨概率,因为给那些未使用的组件命名会让人觉得代码需要它们:

static void ShowForecast()
{
    var (city, high, _, _) = GetForecast();
    Console.WriteLine($"{city}: high {high}°C");

    static (string City, int High, int Low, int RainChance) GetForecast() =>
        ("Portland", 18, 9, 40);
}

当对象的 Deconstruct 方法生成多个值时,相同的放弃语法有效。 有关这些形式,请参阅 解构元组和其他类型

对具有 out 参数的方法的调用

假设输入字段仅当它表示整数时才接受文本。 TryParse(String, Int32) 方法返回一个 bool,用于指示解析是否成功。 它还通过其 int 参数生成解析后的 out。 以下代码只需要布尔结果才能接受或拒绝输入:

static void CheckInput()
{
    string text = "42";

    if (IsWholeNumber(text))
    {
        Console.WriteLine($"Accepted: {text}");
    }
    else
    {
        Console.WriteLine("Enter a whole number.");
    }

    static bool IsWholeNumber(string text) => int.TryParse(text, out _);
}

仅当只关心操作是否成功时,才使用 out _。 弃元明确表明不需要解析出的数字。 如果以后的代码需要数字,请 out 为参数指定一个名称,例如 out int number,并改为保留该值。

弃元赋值 _ = expression 会计算一个表达式,并有意忽略其结果。 当表达式本身无法作为合法语句时,这样做有时会很有用。

Important

请勿在应用程序代码中使用 _ = Task.Run(...)_ = SomeAsyncMethod() 来丢弃任务。 等待该任务,以便其完成和异常都保留在调用流中。 将结果赋给弃元并不能让任务变得安全、观察其异常,或创建受支持的即发即弃操作。

标记未使用的 Lambda 参数

一个EventHandler接收一个object?发送方和一个EventArgs值。 以下处理程序两个参数都不需要;它只会将 "Timer tick" 写入控制台。 命名这两个参数 _ 会使其未使用的状态可见,而无需发明正文从未使用的名称:

static void ShowLambdaDiscards()
{
    EventHandler handler = (_, _) => Console.WriteLine("Timer tick");
    handler(null, EventArgs.Empty);
}

当委托签名需要 lambda 表达式主体未使用的输入时,请选择弃元参数。 如果 lambda 只命名 _了一个参数, _ 则保留一个普通参数名称以实现向后兼容性。

避免 _ 作为标识符

_ 在 C# 不将其识别为弃元的上下文中,可以是普通标识符。 命名 _ 的作用域内变量可以接收类似于放弃赋值的赋值。 在模式上下文中,名为 _ 的可访问常量或类型还可能会改变对 _ 的解释方式。 避免自行声明名称为 _ 的变量、常量或类型;请使用 _ 表示丢弃意图。

另见