C'中discards有什么优势

问题描述 投票:0回答:3

我刚刚在 C# 中遇到了丢弃,并且想知道一些我认为关于丢弃的 Microsoft 文档 没有很好解释的事情。

  1. 使用独立的丢弃只是为了提高可读性吗?如果我有一个返回结果的函数(不一定需要),比如说
    bool
    int
    ,但也做了一些其他逻辑,那么当您可以简单地在作业?

例如:

TcpClient client = new TcpClient();
NetworkStream nc = tcpClient.GetStream();
// what's the difference between
nc.Read(someBuffer, 0, someSize);
// and the discard
_ = nc.Read(someBuffer, 0, someSize);

他们不是都会放弃结果吗?这看起来对我来说纯粹是一种偏好。

  1. 在微软关于丢弃的文档中,回避了它会减少内存分配,这是因为它们相当于未分配的变量吗?

  2. 丢弃的性能优势是什么(如果有的话),这只是为了提高可读性而设计的吗?

更明确地说:我只是好奇使用丢弃是否有任何潜在的性能优势。我提供的 Microsoft 文档链接指出

只有一个丢弃变量,并且该变量可能不存在 即使分配了存储,丢弃也可以减少内存分配

在哪种用例(模式匹配、调用不带 out 的方法、元组解构和/或独立)中内存分配会减少?

c#
3个回答
24
投票

一般来说,在这句话中使用discard是没有意义的:

_ = nc.Read(someBuffer, 0, someSize);

因为你可以忽略返回值。我从来没有让任何人使用独立的丢弃,但文档涵盖了一些有用的特定情况。

当您必须提供变量但不需要它时,将使用丢弃。
正如所提供的文档页面中已经介绍的,丢弃对于以下方面非常有用:

模式匹配

switch (stream)
{
    case MemoryStream _:
    case FileStream _:
        ProcessStream(stream);
        break;
}

不带参数的方法

如果你想检查是否可以将字符串解析为整数,但不关心结果:

if (int.TryParse(str, out _))
{
    // do something
}

否则,您将必须声明一个 out 变量,您不会使用该变量,并且会消耗一些内存。

解构

(_, _, area) = city.GetCityInformation(cityName);

如果没有丢弃,您会将结果解构为 3 个不同的变量,并仅使用其中之一。通过丢弃,代码的意图更加清晰,并且在内存管理方面更加无效。


3
投票

我相信这更多地涉及初始内存分配,而不仅仅是内存管理。因此,如果您不使用输出变量,那么无论它是否是引用类型,它仍然会被推入堆栈。 (是的,所以你问题中的 val 类型不会,我明白你的观点。)但是如果你正在处理类似文件流的东西并且没有关闭流,那么我相信你会坚持下去应用程序生命周期。也就是说,您必须注意任何实现 IDisposable 的事情。我认为丢弃物在这方面可能会产生相对更大的影响。

过去,处理传递给函数的参数,它会阻止这些变量的初始内存分配,因为您不会使用它们。它可能不会对较小的项目产生巨大影响,但如果您有某种方法在应用程序中过度使用,那么它的使用比仅仅一些新的流行风格更适用。


0
投票

丢弃相当于未赋值的变量;它们没有价值。因为只有一个丢弃变量,并且该变量甚至可能没有分配存储空间,所以丢弃可以减少内存分配。因为它们使代码的意图变得清晰,所以增强了代码的可读性和可维护性。 它们基本上是一种忽略与执行操作无关的局部变量的方法,就像当您调用返回值的方法时一样,但是,您只对它执行的底层操作感兴趣,您不使用该方法的返回值。

正如我们在下面的示例中看到的,当应用程序代码使用某些元组元素但忽略其他元素时,丢弃在处理元组时特别有用:

注意:我从 Microsoft docs 获得了示例,并且我添加了第二个输出只是为了显示差异

public class Example
{
   public static void Main()
   {
       var (_, _, _, pop1, _, pop2) = QueryCityDataForYears("New York City", 1960, 2010);
       var (cityName, _, year1, pop3, _, pop4) = QueryCityDataForYears("New York City", 1980, 2010);

       Console.WriteLine($"Population change, in 1960 to 2010: {pop2 - pop1:N0}");
       Console.WriteLine($"Population change, in {cityName}  from {year1} to 2010: {pop4 - pop3: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 (year1 == 1980) 
            {
                population1 = 7981984;
            }
            if (year2 == 2010) 
            {
                population2 = 8175133;
            }

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

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

//Output
//Population change, in 1960 to 2010: 393,149
//Population change, in New York City  from 1980 to 2010: 193,149
© www.soinside.com 2019 - 2024. All rights reserved.