如何使用linq按自定义类型进行分组

Sté*_*ane 12 .net linq group-by

我有这门课

public class Item
{
       public Coordinate coordinate { get; set; }
        ...
        ...
}
Run Code Online (Sandbox Code Playgroud)

使用Coordinate定义如下:

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; }
}
Run Code Online (Sandbox Code Playgroud)

我希望有一个像这样的linq查询:

var grouped = from it in items
              group it by it.Coordinate into grp
              select grp;
Run Code Online (Sandbox Code Playgroud)

正如MSDN在这里提到的,如果我在Coordinate类上重写Equals,我认为这是可能的:

如果必须将查询变量传递给另一个方法,请使用命名类型.使用键的自动实现属性创建一个特殊类,然后重写Equals和GetHashCode方法.您也可以使用结构,在这种情况下,您不必严格地覆盖这些方法.有关更多信息,请参见如何:实现具有自动实现属性的不可变类

等于Coordinate类的实现:

public override bool Equals(object obj)
{
       var coord = obj as Coordinate;
       if(coord == null) return false;
       return (Latitude == coord.Latitude && Longitude == coord.Longitude);
}
Run Code Online (Sandbox Code Playgroud)

我仍然无法通过类似的坐标将我的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());
}
Run Code Online (Sandbox Code Playgroud)

GrouBy方法有一个重载,它将IEqualityComparer作为参数,但使用group子句是否存在等价物?难道我做错了什么??有什么想法吗?

Jon*_*eet 23

您已经展示了Equals实现,但没有展示GetHashCode.您需要覆盖(并以一致的方式)分组才能工作.

示例GetHashCode实现:

public override int GetHashCode()
{
    int hash = 23;
    hash = hash * 31 + Latitude.GetHashCode();
    hash = hash * 31 + Longitude.GetHashCode();
    return hash;
}
Run Code Online (Sandbox Code Playgroud)

请注意,比较float完全相等的值总是有些冒险 - 但我至少期望您的单元测试通过,因为它们没有执行任何计算.