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