我有以下代码:
// OnlineAccountCategory is a class
var itemsByCategory = Items.GroupBy(x => x.OnlineAccountCategory);
foreach (var items in itemsByCategory)
...
项目是包含1个项目的列表。商品的OnlineAccountCategory
不是null
。但是,当我尝试通过itemsByCategory
时,我会收到NullReferenceException
。在调试模式中,我可以看到itemsByCategory
是GroupedEnumerable
,但如果我展开结果视图,它将告诉它'对象引用未设置为对象的实例& #39;
我不太明白这段代码的问题是什么,因为GroupBy()
没有任何异常,但是在foreach循环中中断了。
答案 0 :(得分:2)
这里的问题是OnlineAccountCategory是引用类型属性(而不是字符串或类似的东西)。按引用类型分组使用发生分组的类的方法GetHashCode()
。
关键是如果GetHashCode()
方法抛出异常(例如,如果它依赖于使用我们的对象的属性null
),GroupBy()
方法赢了& #39; t失败。由于某种原因,它只会返回一个包含异常的GroupedEnumerable
。
// Trying to add this to watch:
Items.First().OnlineAccountCategory.GetHashCode()
// Receiving:
'Items.First().OnlineAccountCategory.GetHashCode()' threw an exception of type
'System.NullReferenceException' int {System.NullReferenceException}
因此,当我们尝试访问集合的元素时,它会落在NullReferenceException
。
要解决这个问题,我们有两种方法:
覆盖我们GetHashCode
的{{1}}方法
所以它不会在错误的值上失败,而不是抛出一个
异常将返回类似0的内容。
按一些值类型分组(例如,
OnlineAccountCategory
)。它将由它组合,因此赢了
失败。
<强>更新强>
当OnlineAccountCategory.Id
方法已经错误地实现(在我的情况下在基类中实现)时,问题将出现仅。默认参考比较器将按预期使用。
我的GetHashCode()
方法如下所示:
GetHashCode()
所以我真的不明白为什么它会在这里打破NullReferenceException。
答案 1 :(得分:1)
我很高兴您解决了问题但我不认为您完全理解错误的原因。
我不太明白这段代码的问题是什么,因为GroupBy()没有任何异常,但在foreach循环中中断了。
在执行foreach
之前您没有看到错误的原因是延迟执行。在您尝试枚举集合之前,GetHashCode
不会被称为。如果GetHashCode
正在抛出NullReferenceException
,那么在您使用foreach
执行查询之前,您将不会知道这一点,这是实际创建组的时间。
当然, root 原因是您的错误GetHashCode
方法,可以在单元测试中轻松检测到。
请注意,在不覆盖GetHashCode
的情况下按引用类型进行分组是完全可以的,因为任何空值都只会放入一个带有null
键的组中(Linq不会尝试调用{{1}在null引用上)。如果要根据实例的值定义不同实例的相等性,而不是默认使用引用相等性,则只需需要覆盖GetHashCode
。