如何强制我的lambda表达式提前评估?修复lambda表达式怪异吗?

Dan*_*don 10 .net c# linq lambda

我写了以下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);
}
Run Code Online (Sandbox Code Playgroud)

此代码用于创建一个字典,其中"region id"作为键,并将"location id"列表作为值.

然而,实际发生的是我得到一个字典,其中"region id"作为键,但每个键的值是相同的:它是regionIds中最后一个区域id的位置列表!

看起来这是lambda表达式如何计算的产物.我可以通过将位置ID列表转换为数组来获得正确的结果,但这感觉就像一个kludge.

处理这种情况的好习惯是什么?

m4t*_*mus 11

你正在使用LINQ.您需要执行急​​切操作才能使其执行.Select.ToList()是一个很好的运算符.列表是通用的,可以直接分配给IEnumberable.

在您使用LINQ的情况下,默认情况下会进行延迟评估.ToList/eager操作强制select发生.在使用其中一个运算符之前,不会执行该操作.这就像在ADO.NET中执行SQL一样.如果你有一个声明"Select*from users",它实际上不会执行查询,直到你做额外的事情.ToList使select执行.

  • "贪婪"是误导; 人们通常认为"贪婪"操作是在其操作中使用"贪婪算法"的操作; 也就是说,一种算法试图通过计算本地而非全局的最佳行为来优化其行为.如果你试图简洁地描述"懒惰"或"延迟"计算的反面,则更喜欢"渴望"到"贪婪". (6认同)

asa*_*yer 8

你关闭变量而不是值.

制作变量的本地副本,以便从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);
}
Run Code Online (Sandbox Code Playgroud)

然后读这个:

http://msdn.microsoft.com/en-us/vcsharp/hh264182

编辑 - 强制进行急切的评估也会像其他人建议的那样有效,但大多数时候,热切的评估最终会慢得多.