我有这个班级
public class Item
{
public Coordinate coordinate { get; set; }
...
...
}
坐标的定义如下:
public class Coordinate
{
public Coordinate(float latitude, float longitude)
{
Latitude = latitude;
Longitude = longitude;
}
public float Latitude { get; private set; }
public float Longitude { get; private set; }
}
我希望得到这样的linq查询:
var grouped = from it in items
group it by it.Coordinate into grp
select grp;
As mentioned here by MSDN我认为如果我在我的Coordinate类上重写Equals是可能的:
如果必须通过,请使用命名类型 查询变量到另一个方法。 使用创建一个特殊的类 自动实现的属性 键,然后覆盖等于 和GetHashCode方法。你也可以 使用结构,在这种情况下你不使用 严格来说必须覆盖那些 方法。有关更多信息,请参阅如何 to:实现一个不可变类 具有自动实现的属性
Coordinate类的等于实现:
public override bool Equals(object obj)
{
var coord = obj as Coordinate;
if(coord == null) return false;
return (Latitude == coord.Latitude && Longitude == coord.Longitude);
}
仍然无法通过类似的坐标将我的linq查询分组,因为我的失败的测试显示:
[TestMethod]
public void GroupBy_3ItemsWith2DifferentCoordinates_Returns2Groups()
{
var items = new List<Item>
{
new Item {Coordinate = new Coordinate(10, 10)},
new Item {Coordinate = new Coordinate(10, 10)},
new Item {Coordinate = new Coordinate(12, 10)},
};
var grouped = from it in items
group it by it.Coordinate into g
select g;
Assert.AreEqual(2, grouped.Count());
}
GrouBy方法有一个重载,它将IEqualityComparer作为参数,但使用group子句是否存在等价物? 难道我做错了什么??有什么想法吗?
答案 0 :(得分:23)
您已展示了Equals实现,但未展示GetHashCode。您需要覆盖(并以一致的方式)分组才能工作。
示例GetHashCode实现:
public override int GetHashCode()
{
int hash = 23;
hash = hash * 31 + Latitude.GetHashCode();
hash = hash * 31 + Longitude.GetHashCode();
return hash;
}
请注意,比较float
值以确保完全相等总是有些冒险 - 但我至少期望您的单元测试通过,因为它们没有执行任何计算。
答案 1 :(得分:2)
GrouBy过载 采用IEqualityComparer的方法 作为参数,但是有 相当于使用group子句?
如果您只想要一个快速的内联解决方案并且不担心按键的确切类型,您可以始终按匿名类型进行分组:
var grouped =
from it in items
group it by new {it.Coordinate.Latitude, it.Coordinate.Longitude};