创建C#扩展函数时浮点除法运算无效问题求助
问题分析与解决方案
问题出在LINQ的延迟执行特性上,你调用的Where、OrderBy、Take都是延迟执行的LINQ方法——它们不会立即生成结果集合,而是在每次枚举(比如foreach)时才会重新执行完整的查询逻辑。
具体执行流程:
- 当调用
AddRatingToGame时,函数内的foreach会第一次枚举整个查询链,此时修改了Game对象的rating:除法操作会把原本>8的rating改成小于8。 - 当你在主代码里再次
foreach输出suggestedGames时,会第二次枚举这个查询链,此时Where(g => g.rating > 8f)会重新过滤,但此时所有目标Game的rating已经被改成小于8,自然没有元素输出。 - 乘法操作之所以正常,是因为乘法后rating变得更大,第二次枚举时
Where条件依然满足,所以能输出结果。
解决方案
在调用AddRatingToGame之前,把延迟执行的查询转为立即执行的内存集合,比如用ToList()或者ToArray(),这样查询只会执行一次,后续操作都是在固定集合上进行:
修改主代码:
//providing the random values to the player var suggestedGames = gameList.Where(g => g.rating > 8f) .OrderBy(g => _random.Next()) .Take(3) .ToList() // 转为立即执行的List,固定查询结果 .AddRatingToGame(); // takes 3 random values with 8.0 above rating Console.WriteLine("\nsuggested games:"); foreach(var game in suggestedGames) { Console.WriteLine(game.name); }
也可以直接修改扩展函数,在内部处理为立即执行的集合,避免外部忘记调用ToList:
public static class Helpers { public static IEnumerable<Game> AddRatingToGame(this IEnumerable<Game> games) { var gameList = games.ToList(); // 立即枚举并转为List,避免重复执行查询 foreach(var game in gameList) { game.rating = game.rating / 2f; game.name = $"{game.name} - {game.rating}"; } return gameList; } }
额外优化建议
直接修改原对象的属性容易产生副作用,如果你不想改动原数据,可以考虑创建新的Game对象返回,彻底规避延迟执行的问题:
public static IEnumerable<Game> AddRatingToGame(this IEnumerable<Game> games) { foreach(var game in games) { var newRating = game.rating / 2f; yield return new Game($"{game.name} - {newRating}", newRating); } }
内容的提问来源于stack exchange,提问作者ib_magar
相关产品推荐
相关产品推荐

