在LINQ中使用.ToString():转换值会被缓存还是每次循环重复转换?
关于LINQ中
ToString()是否重复执行的问题 首先明确:在你给出的LINQ to Objects代码里,id.ToString()会在每次迭代时重复执行。因为Where和Any的Lambda表达式每次被调用时,都会执行内部的所有代码——这里的id虽然是外部变量,但ToString()是每次Lambda触发时都会调用的方法,.NET不会自动缓存这个转换结果。
如果是EF这类LINQ to Entities场景,情况会不同:查询会被翻译成SQL,id.ToString()会转为数据库端的CAST操作,不存在客户端重复执行的问题,但你的代码示例更偏向内存集合的LINQ操作,所以重点说前者。
确认该行为的几种实用方法:
自定义带日志的替代方法
写一个简单的包装方法,每次调用就输出日志,替换掉原有的ToString(),运行后看日志输出次数:static string TrackToString(int value) { Console.WriteLine($"TrackToString 被调用,值:{value}"); return value.ToString(); } // 修改查询 var result = data.Where(x => x.SomeField.Any(p => p.Id == TrackToString(id)));如果日志输出次数和
data中元素的迭代次数(或者SomeField的遍历次数)一致,就说明每次都在执行转换。调试器断点验证
直接在Lambda表达式里的id.ToString()处打一个断点,然后启动调试。每次迭代到该代码时,断点都会触发,直观看到重复执行的过程。性能对比测试
提前缓存转换结果,对比两种写法的执行耗时:// 写法1:每次调用ToString var watch1 = Stopwatch.StartNew(); var result1 = data.Where(x => x.SomeField.Any(p => p.Id == id.ToString())).ToList(); watch1.Stop(); // 写法2:提前缓存结果 var idStr = id.ToString(); var watch2 = Stopwatch.StartNew(); var result2 = data.Where(x => x.SomeField.Any(p => p.Id == idStr)).ToList(); watch2.Stop(); Console.WriteLine($"写法1耗时:{watch1.ElapsedTicks}"); Console.WriteLine($"写法2耗时:{watch2.ElapsedTicks}");如果写法1的耗时明显高于写法2,就证明
ToString()在重复执行(数据量越大,差异越明显)。
内容的提问来源于stack exchange,提问作者Diana Gumar
相关产品推荐
相关产品推荐

