C# ToLookup IEqualityComparer参数始终为空

C# ToLookup IEqualityComparer参数始终为空,c#,lookup,C#,Lookup,我无意中遇到了一个奇怪的问题,这对我来说毫无意义 我有一个带有属性位置的业务对象地址(类型为SqlGeography)。为了满足我的需求,我必须查找位置,因为每个确切位置可能有多个地址 由于SqlGeography是一种复杂类型,我怀疑查找可能不起作用,因为出于某种原因它不基于位置坐标,所以我这样做: public class Address { public Address(byte[] location) { Location = SqlGeography.D

我无意中遇到了一个奇怪的问题,这对我来说毫无意义

我有一个带有属性位置的业务对象地址(类型为SqlGeography)。为了满足我的需求,我必须查找位置,因为每个确切位置可能有多个地址

由于SqlGeography是一种复杂类型,我怀疑查找可能不起作用,因为出于某种原因它不基于位置坐标,所以我这样做:

public class Address
{
    public Address(byte[] location)
    {
        Location = SqlGeography.Deserialize(new SqlBytes(location));
    }

    public SqlGeography Location { get; set; }
}

public class SqlGeographyComparer : IEqualityComparer<SqlGeography>
{
    public bool Equals(SqlGeography x, SqlGeography y)
    {
        // !!! always entered but for some reason x + y always null
        if (x == null && y == null)
            return true;
        if (x == null ^ y == null)
            return false;

        return x.STEquals(y).IsTrue;
    }

    public int GetHashCode(SqlGeography obj)
    {
        return obj.GetHashCode();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var addresses = GetAddresses();

        // should be 2 but it's 3 results
        var addressesLookup = addresses.ToLookup(d => d.Location);
        // should be 2 but it's 3 results
        var addressesLookup2 = addresses.ToLookup(d => d.Location, new SqlGeographyComparer());

        Console.ReadLine();
    }

    private static IList<Address> GetAddresses()
    {
        //              230,16,0,0,1,12,213,97,212,23,126,78,72,64,109,51,198,37,82,163,32,64
        var result = new List<Address>();

        result.Add(new Address(new byte[] { 230, 16, 0, 0, 1, 12, 213, 97, 212, 23, 126, 78, 72, 64, 109, 51, 198, 37, 82, 163, 32, 64 }));
        result.Add(new Address(new byte[] { 230, 16, 0, 0, 1, 12, 213, 97, 212, 23, 126, 78, 72, 64, 109, 51, 198, 37, 82, 163, 32, 64 }));

        result.Add(new Address(new byte[] { 230, 16, 0, 0, 1, 12, 213, 97, 212, 23, 126, 78, 72, 64, 109, 51, 198, 37, 82, 163, 32, 63 }));

        return result;
    }
}
公共类地址
{
公共广播(字节[]位置)
{
Location=SqlGeography.Deserialize(新的SqlBytes(Location));
}
公共SqlGeography位置{get;set;}
}
公共类SqlGeographyComparer:IEqualityComparer
{
公共布尔等于(SqlGeography x,SqlGeography y)
{
//!!!始终输入,但由于某些原因x+y始终为空
如果(x==null&&y==null)
返回true;
如果(x==null^y==null)
返回false;
返回x.STEquals(y).IsTrue;
}
public int GetHashCode(SqlGeography obj)
{
返回obj.GetHashCode();
}
}
班级计划
{
静态void Main(字符串[]参数)
{
var addresses=GetAddresses();
//应该是2,但它是3
var addressesLookup=addresses.ToLookup(d=>d.Location);
//应该是2,但它是3
var addressesLookup2=addresses.ToLookup(d=>d.Location,新的SqlGeographyComparer());
Console.ReadLine();
}
私有静态IList GetAddresses()
{
//              230,16,0,0,1,12,213,97,212,23,126,78,72,64,109,51,198,37,82,163,32,64
var result=新列表();
Add(新地址(新字节[]{230,16,0,0,1,12,213,97,212,23,126,78,72,64,109,51,198,37,82,163,32,64});
Add(新地址(新字节[]{230,16,0,0,1,12,213,97,212,23,126,78,72,64,109,51,198,37,82,163,32,64});
Add(新地址(新字节[]{230,16,0,0,1,12,213,97,212,23,126,78,72,64,109,51,198,37,82,163,32,63});
返回结果;
}
}

这是一个奇怪的bug吗?我没听说过ToLookup在哪里不将对象传递到给定的比较器实例

一旦我更改SqlGeographyComparer以覆盖其方法,如下所示:

    public int GetHashCode(SqlGeography obj)
    {
        unchecked
        {
            return ((obj.Lat.GetHashCode() * 397) ^ obj.Long.GetHashCode());
        }
    }
它工作正常

事实证明,GetHashCode必须模拟所需的相等比较(用Equals编写),才能使参数正常工作

实现GetHashCode的参考资料,以防其他人偶然发现此问题并对397感到疑惑:


听起来好像您的
位置
属性从未实际填充过。虽然您的哈希代码实现看起来不正确,但是。。。你能提供一个简短但完整的程序来演示这个问题吗?是的。需要几分钟是的,您需要一个GetHashCode()。只是为了做一个测试(发布时不要做),做一个
返回0。。。好啊从技术上讲,若你们真的只有很少的元素,你们可以在发行版中完成:)但不要告诉任何人我告诉过你们的!:)@JonSkeet用完整的示例更新了问题,GetHashCode不会像您现在这样工作;它需要使用以相等方式比较的值。简单的方法是将您在STEquals中比较的每个项目的GetHashCode XOR在一起。