我有一个Guid
列表,其中保留了我的项目列表中所有重复的Guid
:
IEnumerable<Guid> duplicateExists = ListOfMyItems
.GroupBy(x => x.ID)
.Where(group => group.Count() > 1)
.Select(group => group.Key);
现在,我要检查是否存在重复项,如果存在,请从ListOfMyItems
中删除最后一次出现的重复项。 DeleteItemFromOrder
只是从数据库中删除一行。
这有效:
foreach (var item in duplicateExists)
{
_ = ListOfMyItems.Remove(ListOfMyItems.Last(x => x.ID == item));
MyLogic.DeleteItemFromOrder(Bill.ID, item);
return;
}
这将输入条件if
,然后在DeleteItemFromOrder
上失败,告诉我duplicateExists - sequence contains no elements
:
if(duplicateExists.Any())
{
_ = ListOfMyItems.Remove(ListOfMyItems.Last(x => x.ID == duplicateExists.First()));
MyLogic.DeleteItemFromOrder(Bill.ID, duplicateExists.First());
return;
}
第二个示例为什么失败?
答案 0 :(得分:7)
这是 Linq 延期执行的结果:当您放置
IEnumerable<Guid> duplicateExists = ListOfMyItems
.GroupBy(x => x.ID)
.Where(group => group.Count() > 1)
.Select(group => group.Key);
系统实际上不执行查询;那么你有
if (duplicateExists.Any())
{
_ = ListOfMyItems.Remove(ListOfMyItems.Last(x => x.ID == duplicateExists.First()));
MyLogic.DeleteItemFromOrder(Bill.ID, duplicateExists.First());
return;
}
系统将执行以下操作:
duplicateExists.Any()
并获得true
,因为存在重复项duplicateExists.First()
获取重复项,并从ListOfMyItems
-ListOfMyItems.Remove
duplicateExists.First()
再次执行MyLogic.DeleteItemFromOrder
,由于<{> 1 已修改ListOfMyItems
并且没有重复-duplicateExists
是空 快速补丁:具体化 duplicateExists
, force ,系统执行查询并将结果存储在集合中,例如数组:
IEnumerable<Guid> duplicateExists = ListOfMyItems
.GroupBy(x => x.ID)
.Where(group => group.Count() > 1)
.Select(group => group.Key)
.ToArray();
答案 1 :(得分:2)
尽管第一个代码片段可能有效,但它们都让人感到恐惧。
第一个只能工作,因为GroupBy执行隐式的ToList迭代。
对IEnumerable进行多次迭代需要一些预防措施。 Linq是惰性计算的,两次调用duplicateExists
意味着它再次被执行。 ToList()可以阻止它。
通过以下方式,您将获得更高的安全性和更好的性能:
IEnumerable<Guid> duplicateExists = ListOfMyItems
.GroupBy(x => x.ID)
.Where(group => group.Count() > 1)
.Select(group => group.Key)
.ToList(); // cache the results
关于失败:
if(duplicateExists.Any())
{
// remove item X
_ = ListOfMyItems.Remove(ListOfMyItems.Last(x => x.ID == duplicateExists.First()));
// trying to find X again but duplicateExists is re-evaluated
MyLogic.DeleteItemFromOrder(Bill.ID, duplicateExists.First());
return;
}
答案 2 :(得分:2)
LINQ使用惰性评估。您需要先将初始查询解析为物理列表,然后才能使用它来修改原始数据集,如下所示:
var duplicateExists = ListOfMyItems
.GroupBy(x => x.ID)
.Where(group => group.Count() > 1)
.Select(group => group.Key)
.ToArray();