IEnumerable<T>.Contains 默认不使用我自己的 IEqualityComparer
IEnumerable<T>.Contains is not using my own IEqualityComparer by default
我实现了 IEqualityComparer
,但得到的比较不正确,甚至没有看到调试器在被 IEnumerable.Contains
方法使用时通过我的 Equals
方法。
public struct CustomMailAddress : IEqualityComparer<CustomMailAddress>
{
public string Address { get; private set; }
public string DisplayName { get; private set; }
public bool IsFullAddress { get; private set; }
public CustomMailAddress(string address)
{
this.Address = address;
this.DisplayName = String.Empty;
this.IsFullAddress = address.IndexOf('@') >= 0;
}
public CustomMailAddress(MailAddress address)
{
this.Address = address.Address;
this.DisplayName = address.DisplayName;
this.IsFullAddress = true;
}
public bool Equals(CustomMailAddress x, CustomMailAddress y)
{
return x.IsFullAddress ? x.Address.EndsWith(y.Address) : y.Address.EndsWith(x.Address);
}
public int GetHashCode(CustomMailAddress obj)
{
return obj.Address.GetHashCode();
}
}
基于 MSDN documentation :
Elements are compared to the specified value by using the default equality comparer, Default.
这导致:
The default instance of the EqualityComparer class for type T.
据我了解,他们说将使用我自己的比较器。但是这个 returns false
:
bool isMatch = source.CollectedAddresses.Any(x => _validAddreses.Contains(x));
所以,因为它应该 return true
并且调试器没有在我的 Equals
方法处停止,所以我使用了 Contains
overload,得到我想要的 true
.
bool isMatch = source.CollectedAddresses.Any(x => _validAddreses.Contains(x, new CustomMailAddress()));
我错过了什么?不是应该使用 EqualityComparer
我的 CustomMailAddress
有 "by default" 吗?
请记住,实施 IEqualityComparer
意味着 class CustomMailAddress
可以比较类型 CustomMailAddress
的对象,例如public struct AppleComparer: IEqualityComparer<Apple>
表示 AppleComparer
可以比较苹果。
您真正想要的是覆盖 Equals 和 GetHashCode
public struct CustomMailAddress
{
public string Address { get; private set; }
public string DisplayName { get; private set; }
public bool IsFullAddress { get; private set; }
public CustomMailAddress(string address)
{
this.Address = address;
this.DisplayName = String.Empty;
this.IsFullAddress = address.IndexOf('@') >= 0;
}
public CustomMailAddress(MailAddress address)
{
this.Address = address.Address;
this.DisplayName = address.DisplayName;
this.IsFullAddress = true;
}
public override bool Equals(object obj)
{
if ((obj is CustomMailAddress y))
{
return this.IsFullAddress ? this.Address.EndsWith(y.Address) : y.Address.EndsWith(this.Address);
}
return false;
}
public override int GetHashCode()
{
return Address.GetHashCode();
}
}
From my understanding, they say my own comparer will be used.
他们从来没有这么说过。你误会了。如果你的理解是正确的,他们会说类似 "if T
implements IEqualityComparer<T>
, an instance of T
is returned".
但是想想看,IEqualityComparer<T>.Default
怎么会知道return一个T
的实例呢?你没有保证任何无参数构造函数或类似的东西!
"default equality comparer" 实际上调用了 IEquatable<T>
的 Equals
方法,所以我想你可能混淆了这两个接口。你的结构应该实现 IEquatable<T>
,而不是 IEqualityComparer
.
我实现了 IEqualityComparer
,但得到的比较不正确,甚至没有看到调试器在被 IEnumerable.Contains
方法使用时通过我的 Equals
方法。
public struct CustomMailAddress : IEqualityComparer<CustomMailAddress>
{
public string Address { get; private set; }
public string DisplayName { get; private set; }
public bool IsFullAddress { get; private set; }
public CustomMailAddress(string address)
{
this.Address = address;
this.DisplayName = String.Empty;
this.IsFullAddress = address.IndexOf('@') >= 0;
}
public CustomMailAddress(MailAddress address)
{
this.Address = address.Address;
this.DisplayName = address.DisplayName;
this.IsFullAddress = true;
}
public bool Equals(CustomMailAddress x, CustomMailAddress y)
{
return x.IsFullAddress ? x.Address.EndsWith(y.Address) : y.Address.EndsWith(x.Address);
}
public int GetHashCode(CustomMailAddress obj)
{
return obj.Address.GetHashCode();
}
}
基于 MSDN documentation :
Elements are compared to the specified value by using the default equality comparer, Default.
这导致:
The default instance of the EqualityComparer class for type T.
据我了解,他们说将使用我自己的比较器。但是这个 returns false
:
bool isMatch = source.CollectedAddresses.Any(x => _validAddreses.Contains(x));
所以,因为它应该 return true
并且调试器没有在我的 Equals
方法处停止,所以我使用了 Contains
overload,得到我想要的 true
.
bool isMatch = source.CollectedAddresses.Any(x => _validAddreses.Contains(x, new CustomMailAddress()));
我错过了什么?不是应该使用 EqualityComparer
我的 CustomMailAddress
有 "by default" 吗?
请记住,实施 IEqualityComparer
意味着 class CustomMailAddress
可以比较类型 CustomMailAddress
的对象,例如public struct AppleComparer: IEqualityComparer<Apple>
表示 AppleComparer
可以比较苹果。
您真正想要的是覆盖 Equals 和 GetHashCode
public struct CustomMailAddress
{
public string Address { get; private set; }
public string DisplayName { get; private set; }
public bool IsFullAddress { get; private set; }
public CustomMailAddress(string address)
{
this.Address = address;
this.DisplayName = String.Empty;
this.IsFullAddress = address.IndexOf('@') >= 0;
}
public CustomMailAddress(MailAddress address)
{
this.Address = address.Address;
this.DisplayName = address.DisplayName;
this.IsFullAddress = true;
}
public override bool Equals(object obj)
{
if ((obj is CustomMailAddress y))
{
return this.IsFullAddress ? this.Address.EndsWith(y.Address) : y.Address.EndsWith(this.Address);
}
return false;
}
public override int GetHashCode()
{
return Address.GetHashCode();
}
}
From my understanding, they say my own comparer will be used.
他们从来没有这么说过。你误会了。如果你的理解是正确的,他们会说类似 "if T
implements IEqualityComparer<T>
, an instance of T
is returned".
但是想想看,IEqualityComparer<T>.Default
怎么会知道return一个T
的实例呢?你没有保证任何无参数构造函数或类似的东西!
"default equality comparer" 实际上调用了 IEquatable<T>
的 Equals
方法,所以我想你可能混淆了这两个接口。你的结构应该实现 IEquatable<T>
,而不是 IEqualityComparer
.