如何强制我的lambda表达式早期评估?修复lambda表达式的怪异
本文关键字:表达式 lambda 修复 何强制 我的 评估 | 更新日期: 2023-09-27 18:03:28
我写了以下c#代码:
_locationsByRegion = new Dictionary<string, IEnumerable<string>>();
foreach (string regionId in regionIds)
{
IEnumerable<string> locationIds = Locations
.Where(location => location.regionId.ToUpper() == regionId.ToUpper())
.Select(location => location.LocationId); //If I cast to an array here, it works.
_locationsByRegion.Add(regionId, LocationIdsIds);
}
这段代码的目的是创建一个字典,我的"区域id"作为键,"位置id"列表作为值。
然而,实际发生的是,我得到一个字典与"区域id"作为键,但每个键的值是相同的:它是在regionid的最后一个区域id的位置列表!
看起来这是lambda表达式的求值方式的乘积。我可以通过将位置id列表强制转换为一个数组来获得正确的结果,但这感觉像是一个拼凑。
处理这种情况的好做法是什么?
您正在使用LINQ。您需要执行一个急切操作来使它执行. select。ToList()是一个很好的操作符。List是泛型的,可以直接赋值给IEnumberable。
在使用LINQ的情况下,它默认执行惰性求值。ToList/eager操作强制执行选择。在使用这些操作符之前,不会执行操作。这就像在ADO中执行SQL。NET之类的。如果您有语句"Select * from users",它实际上不会执行查询,直到您做了额外的事情。ToList使select执行。
关闭变量,而不是值。
创建变量的本地副本,以便从foreach循环中捕获当前值:
_locationsByRegion = new Dictionary<string, IEnumerable<string>>();
foreach (string regionId in regionIds)
{
var regionToUpper = regionId.ToUpper();
IEnumerable<string> locationIds = Locations
.Where(location => location.regionId.ToUpper() == regionToUpper)
.Select(location => location.LocationId); //If I cast to an array here, it works.
_locationsByRegion.Add(regionId, LocationIdsIds);
}
然后读这个:
http://msdn.microsoft.com/en-us/vcsharp/hh264182edit -强制动态求值也可以像其他人建议的那样工作,但是大多数情况下动态求值最终会慢得多。
在Select(...)
之后调用ToList()
或ToArray()
。
实际上这个问题是关于查找创建的,这可以通过标准LINQ组连接更简单地实现:
var query = from regionId in regionIds
join location in Locations
on regionId.ToLower() equals location.regionId.ToLower() into g
select new { RegionID = regionId,
Locations = g.Select(location => location.LocationId) };
在这种情况下,所有的位置将被一次下载,并分组在内存中。此外,在您尝试访问结果或将其转换为dictionary之前,不会执行此查询:
var locationsByRegion = query.ToDictionary(x => x.RegionID, x => x.Locations);