【问题标题】:Discard feature significance in C# 7.0?放弃 C# 7.0 中的特征重要性?
【发布时间】:2018-08-04 20:03:19
【问题描述】:

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

Discards 是局部变量,可以赋值但不能读取 从。即它们是“只写”局部变量。

然后,一个例子如下:

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

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

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

【问题讨论】:

  • 有时你需要一个方法,但只需要一些输出。如果你不使用discard,那么当其他人阅读代码时,他们可能会想知道你用isOK做了什么,或者你为什么使用它。有一个丢弃,这是显而易见的。这不是必需的,但是当您不关心输出,想要明确并且不想想一个聪明的句柄时,这是一件好事。

标签: c# c#-7.0


【解决方案1】:

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

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;
}

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

我发现您提供的链接中显示的示例有点误导。如果我尝试将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);
}

从我阅读上面的代码可以看出,discards 似乎与C# 的最新版本中引入的其他范例相比具有更高的效能,例如tuples deconstruction


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

fileparts function 请求所有三个可能的输出:

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

当前工作区现在包含来自文件部分的三个变量:helpPath、name 和 ext。在这种情况下,变量很小。但是,某些函数返回的结果会占用更多内存。如果您不需要这些变量,它们会浪费您的系统空间。

使用波浪号 (~) 忽略第一个输出:

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

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

【讨论】:

    【解决方案2】:

    我多次按照这些思路编写代码:

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

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

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

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

    【讨论】:

      【解决方案3】:

      我看到主要针对返回 Task&lt;T&gt; 但您不想 await 输出的方法使用丢弃。

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

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

      除此之外会产生以下警告:

      CS4014 因为没有等待这个调用,所以执行 当前方法在调用完成之前继续。考虑 将 'await' 运算符应用于调用结果。

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

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

      没有更多警告。

      【讨论】:

      • 只是补充一点,CS40​​14 警告文本已被修改,建议您在不想等待时使用 _ 丢弃,这使得这门大炮变得异常。作为我曾经使用过它的一个例子,我有一个异步方法可以加载一些数据,如果你想等待它,它会返回数据,但如果你愿意,它还有一个可选参数来提供回调您的方法继续并稍后捕获加载完成的事件+数据。
      【解决方案4】:

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

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

      _ = myParam ?? throw new MyException();
      

      【讨论】:

        【解决方案5】:

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

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

        有关丢弃模式的列表,请参阅这篇文章:Discards

        【讨论】:

        • 这种情况下,discard是默认的switch case——必须放在最后,否则后面的case永远不会被执行。
        【解决方案6】:

        考虑一下:

        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
        

        【讨论】:

          猜你喜欢
          • 2018-12-14
          • 2021-12-23
          • 2021-02-03
          • 2016-11-07
          • 1970-01-01
          • 2022-07-17
          • 2020-12-22
          • 2019-02-28
          • 1970-01-01
          相关资源
          最近更新 更多