放弃 C# 7.0 中的功能重要性?

Discard feature significance in C# 7.0?

在体验新的 C# 7.0 功能时,我坚持使用 discard 功能。它说:

Discards are local variables which you can assign but cannot read from. i.e. they are “write-only” local variables.

然后,示例如下:

if (bool.TryParse("TRUE", out bool _))

什么是真正有用的用例?我的意思是如果我以正常方式定义它会怎样,比如:

if (bool.TryParse("TRUE", out bool isOK))

discards 基本上是一种故意忽略与生成代码目的无关的局部变量的方法。这就像当你调用一个方法时 returns 一个值,但是,由于你只对它执行的底层操作感兴趣,你不会将它的输出分配给调用方方法中定义的局部变量,例如:

public static void Main(string[] args)
{
    // I want to modify the records but I'm not interested
    // in knowing how many of them have been modified.
    ModifyRecords();
}

public static Int32 ModifyRecords()
{
    Int32 affectedRecords = 0;

    for (Int32 i = 0; i < s_Records.Count; ++i)
    {
        Record r = s_Records[i];

        if (String.IsNullOrWhiteSpace(r.Name))
        {
            r.Name = "Default Name";
            ++affectedRecords;
        }
    }

    return affectedRecords;
}

实际上,我将其称为装饰性特征...从某种意义上说,它是一种设计时特征(无论如何都会执行有关丢弃变量的计算),有助于保持代码清晰、可读且易于维护。

我发现您提供的 link 中显示的示例有点误导。如果我尝试将 String 解析为 Boolean,我很可能想在我的代码中的某处使用解析后的值。否则我只会尝试查看 String 是否对应于 Boolean 的文本表示(例如 regular expression...即使是简单的 if 语句也可以如果外壳处理得当,工作)。我并不是说这永远不会发生或这是一种不好的做法,我只是说这不是您可能需要生成的最常见的编码模式。

相反,this article 中提供的示例真正展示了此功能的全部潜力:

public static void Main()
{
    var (_, _, _, pop1, _, pop2) = QueryCityDataForYears("New York City", 1960, 2010);
    Console.WriteLine($"Population change, 1960 to 2010: {pop2 - pop1:N0}");
}

private static (string, double, int, int, int, int) QueryCityDataForYears(string name, int year1, int year2)
{
    int population1 = 0, population2 = 0;
    double area = 0;

    if (name == "New York City")
    {
        area = 468.48;

        if (year1 == 1960) {
            population1 = 7781984;
        }

        if (year2 == 2010) {
            population2 = 8175133;
        }

        return (name, area, year1, population1, year2, population2);
    }

    return ("", 0, 0, 0, 0, 0);
}

从我阅读上面的代码可以看出,似乎 discardsC# 的最新版本中引入的其他范例(如 tuples deconstruction)具有更高的协同作用。


对于 Matlab 程序员来说,discards 远不是一个新概念,因为编程语言在非常非常非常长的时间(可能从一开始就实现了它们,但我不能肯定地说)。官方文档对它们的描述如下(link here):

Request all three possible outputs from the fileparts function:

helpFile = which('help');
[helpPath,name,ext] = fileparts('C:\Path\data.txt');

The current workspace now contains three variables from fileparts: helpPath, name, and ext. In this case, the variables are small. However, some functions return results that use much more memory. If you do not need those variables, they waste space on your system.

Ignore the first output using a tilde (~):

[~,name,ext] = fileparts(helpFile);

唯一的区别是,在 Matlab 中,通常会跳过丢弃输出的内部计算,因为输出参数是灵活的,您可以知道调用者请求了多少个以及其中一个。

很多次我都按照这些行编写代码:

TextBox.BackColor = int32.TryParse(TextBox.Text, out int32 _) ? Color.LightGreen : Color.Pink;

请注意,这将是更大数据集合的一部分,而不是独立的数据。这个想法是针对他们输入的数据的每个字段的有效性提供即时反馈。

我使用浅绿色和粉红色,而不是人们期望的绿色和红色——后一种颜色足够深,以至于文本变得有点难以阅读,而浅色版本的含义仍然非常明显。

(在某些情况下,我也有一个 Color.Yellow 来标记一些无效但也不是完全无效的东西。假设解析器将接受分数并且该字段当前包含“2 1”。那可能是“2 1/2”的一部分,所以它不是垃圾,但也不是有效的。)

我看到丢弃主要用​​于 return Task<T> 但你不想 await 输出的方法。

所以在下面的例子中,我们不想等待 SomeOtherMethod() 的输出,所以我们可以这样做:

//myClass.cs
public async Task<bool> Example() => await SomeOtherMethod()

// example.cs
Example();

否则将生成以下警告:

CS4014 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

为了减轻此警告并从根本上确保编译器我们知道我们在做什么,您可以使用丢弃:

//myClass.cs
public async Task<bool> Example() => await SomeOtherMethod()

// example.cs
_ = Example();

没有更多警告。

为上述答案添加另一个用例。

您可以将丢弃与空合并运算符结合使用,以便在您的函数开始时进行漂亮的单行空检查:

_ = myParam ?? throw new MyException();

丢弃模式也可以与 switch 表达式一起使用。

string result = shape switch
{
     Rectangule r => $"Rectangule",
     Circle c => $"Circle",
     _ => "Unknown Shape"
};

有关带弃牌的形态列表,请参阅这篇文章:Discards

考虑一下:

5 + 7;

此“语句”执行评估但未分配给某物。它将立即以 CS 错误代码 CS0201 突出显示。

// Only assignment, call, increment, decrement, and new object expressions can be used as a statement

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0201?f1url=%3FappId%3Droslyn%26k%3Dk(CS0201)

此处使用的丢弃变量不会改变它是一个未使用表达式的事实,相反,它会让编译器、您和其他检查您的代码的人认为它是有意未使用的。

_ = 5 + 7; //acceptable