我有这个带比较器的课程
public partial class CityCountryID :IEqualityComparer<CityCountryID>
{
public string City { get; set; }
public string CountryId { get; set; }
public bool Equals(CityCountryID left, CityCountryID right)
{
if ((object)left == null && (object)right == null)
{
return true;
}
if ((object)left == null || (object)right == null)
{
return false;
}
return left.City.Trim().TrimEnd('\r', '\n') == right.City.Trim().TrimEnd('\r', '\n')
&& left.CountryId == right.CountryId;
}
public int GetHashCode(CityCountryID obj)
{
return (obj.City + obj.CountryId).GetHashCode();
}
}
我尝试使用Hashset和Distinct,但两个都没有工作。我不想在db中这样做,因为列表太大而且对于everrrrrrrr来说也是如此。为什么这不适用于c#? 我想获得一个独特的国家/地区列表。
List<CityCountryID> CityList = LoadData("GetCityList").ToList();
//var unique = new HashSet<CityCountryID>(CityList);
Console.WriteLine("Loading Completed/ Checking Duplicates");
List<CityCountryID> unique = CityList.Distinct().ToList();
答案 0 :(得分:5)
您的Equals
和GetHashCode
方法不一致。在Equals
中,您正在修剪城市名称 - 但在GetHashCode
中您不是。这意味着两个相等的值可能具有不同的哈希码,违反了正常的契约。
这是第一件要解决的问题。我建议修剪数据库中的城市名称以获得理智,然后删除Trim
检查中的Equality
操作。这会让事情变得更简单。
第二个是解决为什么在数据库中花了很长时间:我强烈期望它在数据库中的表现要比本地好,特别是如果你有两个字段的索引。
接下来要考虑尽可能使你的类型不可变。允许对象的可变属性影响相等性通常是个坏主意;如果在将对象用作字典中的键(或将其添加到HashSet
之后)更改对象的等同敏感属性后,您可能会发现无法再次检索它,即使使用了确切的同样的参考。
编辑:另外,正如Scott指出的那样,你要么需要传入IEqualityComparer
来执行相等比较或让你的类型覆盖正常{ {1}}和Equals
方法。目前你正处于两者之间(实现GetHashCode
,但实际上没有提供比较器作为IEqualityComparer<T>
或Distinct
构造函数的参数。通常,类型为自己实现HashSet
是不寻常的。基本上,您 在或类型中实现“自然”相等性检查,您在实现IEqualityComparer
的类型中实现独立的相等性检查。您没有 来实施IEqualityComparer<T>
- 只是覆盖正常的IEquatable<T>
方法会起作用 - 但同时实施Equals(object)
通常是个好主意
另外,我还建议在不使用字符串连接的情况下计算哈希码。例如:
IEquatable<T>
答案 1 :(得分:3)
您需要界面IEquatable<T>
而不是IEqualityComparer<T>
(请务必阅读文档,尤其是“对实施者的说明”部分!)。 IEqualityComparer是您希望使用自定义比较器而不是内置于类中的默认比较器。
此外,您需要进行Jon mentioned GetHashCode
与Equals
不匹配的更改