C# yield return详解。

场景:
假如一个集合中有一百万条数据,我们只想要前1000条。

错误代码示范

     foreach (var c in GetCustomers(1000000))
            {
                if (c.Id < 1000)
                {
                    Console.WriteLine($"ID:{c.Id},Name:{c.Name}");
                }
                else 
                {
                    break;
                }
               
            }



            Console.Read();





   static IEnumerable<Customer> GetCustomers(int count)
        {
            List<Customer> listcustomers = new List<Customer>();
            for (int i = 0; i < count; i++)
            {
                var customer = new Customer
                {
                    Id = i,
                    Name = $"Name{i}"
                };
                listcustomers.Add(customer);


            }
            return listcustomers;
        }

这种代码有个很大的错误就是,我们明明只需要1000条数据,它却创建了一百万条数据,极大的浪费了内存。

正确示范,使用yield return关键字。

   foreach (var c in GetCustomersYield(1000000))
            {
                if (c.Id < 1000)
                {
                    Console.WriteLine($"ID:{c.Id},Name:{c.Name}");
                }
                else 
                {
                    break;
                }
               
            }



            Console.Read();

 static IEnumerable<Customer> GetCustomersYield(int count) 
        {
            for (int i = 0; i < count; i++)
            {

                yield return new Customer { 
                Id=i,
                Name=$"Name{i}"
                };


            }
        }

通过运行代码可以看到,GetCustomersYield(1000000)不会立刻去创建实体,甚至代码不会直接运行GetCustomersYield 这个方法,他会先走循环,然后根据循环体需求,去创建数据。yield return底层是对迭代器的实现。所以方法可以直接返回IEnumerable<Customer> 类型,除非数据必须使用,不然yield return返回的对象是不会被立即创建的,有点懒加载的意思。实际上yield return返回的并不是数据,而是数据的迭代。通过多次叠加,其实循环遍历的结果,就是迭代器的集合。这样使用yield return关键字就只创建出来了1000条数据,大大的节省了内存开销。

接下来我们对 上面的2个代码 示例做下性能对比 。

Nuget 下载BenchmarkDotNet跑分工具。
单独创建一个BenchmarkTest类去跑


    [MemoryDiagnoser]
    public class BenchmarkTest
    {

        [Benchmark]
        public void ProcessCustomer() 
        {
            var customers = GetCustomers(1000000);
            foreach (var c in customers)
            {
                if (c.Id < 1000)
                {
                    Console.WriteLine($"ID:{c.Id},Name:{c.Name}");
                }
                else
                {
                    break;
                }

            }

        }


        [Benchmark]
        public void ProcessCustomerYield()
        {
            var customers = GetCustomersYield(1000000);
            foreach (var c in customers)
            {
                if (c.Id < 1000)
                {
                    Console.WriteLine($"ID:{c.Id},Name:{c.Name}");
                }
                else
                {
                    break;
                }

            }


        }

        static IEnumerable<Customer> GetCustomers(int count)
        {
            List<Customer> listcustomers = new List<Customer>();
            for (int i = 0; i < count; i++)
            {
                var customer = new Customer
                {
                    Id = i,
                    Name = $"Name{i}"
                };
                listcustomers.Add(customer);


            }
            return listcustomers;
        }
        static IEnumerable<Customer> GetCustomersYield(int count)
        {
            for (int i = 0; i < count; i++)
            {

                yield return new Customer
                {
                    Id = i,
                    Name = $"Name{i}"
                };


            }
        }

    }

切记类上和方法上要加上对应的特性。

主方法调用

  static void Main(string[] args)
        {

          var sumery =  BenchmarkRunner.Run<BenchmarkTest>();
          }

Benchmark只能在Release版本进行跑分,打开项目根目录。然后文件夹上 cmd
输入如下命令生成Release

dotnet build -c Release

在这里插入图片描述

拿到画线的地址,执行如下命令

dotnet D:\test\集合操作\集合操作\bin\Release\net5.0\集合操作.dll

等待跑分结果,如图:
在这里插入图片描述

C#课程欢迎留言或者私聊。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
yield returnC#中的一个关键字,用于在迭代器方法中返回一个元素,并暂停迭代器的执行,直到下一次迭代。通过使用yield return,可以在不立即计算所有元素的情况下,逐个返回元素。 引用\[1\]中展示了一个使用yield return实现的过滤器方法。该方法通过遍历初始数据集合,并返回大于2的元素。每次调用迭代器方法时,只返回一个元素,并在下一次迭代时继续执行。 引用\[2\]展示了一个不使用yield return的实现。该方法通过创建一个结果列表,并在遍历初始数据集合时,将大于2的元素添加到列表中。最后,返回结果列表。 引用\[3\]展示了一个正确使用yield return的示例。该示例使用yield return返回一个包含指定数量的Customer对象的迭代器。在使用foreach循环遍历迭代器时,只打印ID小于1000的Customer对象,并在遇到ID大于等于1000的对象时终止循环。 总结来说,yield returnC#中用于在迭代器方法中逐个返回元素的关键字。它可以帮助我们在不立即计算所有元素的情况下,按需返回元素,并暂停迭代器的执行。 #### 引用[.reference_title] - *1* *2* [C#yield return用法分析](https://blog.csdn.net/wojiuguowei/article/details/124604083)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [C# yield return详解。](https://blog.csdn.net/csdn2990/article/details/129664309)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值