C# yield return详解。

文章通过对比错误代码和正确示范,展示了在处理大量数据时如何利用yieldreturn关键字优化内存使用。错误做法是预先创建一百万条数据,而正确做法是使用yieldreturn按需生成,仅创建所需的1000条数据。通过BenchmarkDotNet进行性能测试,证明了优化方法的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

场景:
假如一个集合中有一百万条数据,我们只想要前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#课程欢迎留言或者私聊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值