C#中GroupJoin查询返回结果的疑惑及原理咨询
先看你给出的代码定义:
public class Item { public int Id { get; set;} public decimal Amount { get; set;} } var itemListOne = new List<Item>(){ new Item{ Id = 1, Amount = 100 }, new Item{ Id = 2, Amount = 200 }, new Item{ Id = 3, Amount = 300 }, }; var itemListTwo = new List<Item>(){ new Item{ Id = 1, Amount = 400 }, new Item{ Id = 2, Amount = 500 } };
以及你执行的LINQ查询:
var result = (from listOneItem in itemListOne join listTwoItem in itemListTwo on listOneItem.Id equals listTwoItem.Id into joinedItems from joinedItem in joinedItems.DefaultIfEmpty() select joinedItem != null ? joinedItem.Amount : 0).ToArray();
咱们一步步拆解这段代码的执行逻辑:
第一步:GroupJoin分组
join ... into joinedItems这行是LINQ的GroupJoin操作,它会遍历itemListOne的每个元素(也就是listOneItem),然后在itemListTwo里找出所有Id和当前listOneItem.Id相等的元素,把这些元素打包成一个集合,赋值给joinedItems。
对应到你的数据:- 当
listOneItem.Id=1时,joinedItems里只有itemListTwo中Id=1的元素(Amount=400) - 当
listOneItem.Id=2时,joinedItems里只有itemListTwo中Id=2的元素(Amount=500) - 当
listOneItem.Id=3时,itemListTwo里没有匹配的元素,所以joinedItems是空集合
- 当
第二步:展开分组并处理空值
from joinedItem in joinedItems.DefaultIfEmpty()这行是把分组后的集合“展开”成单个元素。DefaultIfEmpty()的作用是:如果joinedItems是空集合,就返回一个包含默认值(引用类型默认是null)的集合。
所以这一步之后,每个listOneItem都会对应一个joinedItem:- Id=1的listOneItem对应
joinedItem是itemListTwo的Id=1元素 - Id=2的listOneItem对应
joinedItem是itemListTwo的Id=2元素 - Id=3的listOneItem对应
joinedItem是null
- Id=1的listOneItem对应
第三步:选择结果
最后select joinedItem != null ? joinedItem.Amount : 0明确指定了要取的是joinedItem的Amount——也就是itemListTwo中匹配到的元素的金额,没有匹配到(joinedItem为null)就返回0。这就是为什么你得到的结果是[400,500,0],而不是itemListOne的金额。
如果你的需求是返回itemListOne的金额,只需要把select的部分改成select listOneItem.Amount即可,这样结果就是[100,200,300]。
内容的提问来源于stack exchange,提问作者William

