C# 优先选择平等比较者<;T>;致IEqualityComparer<;T>;
从MSDN的备注部分:C# 优先选择平等比较者<;T>;致IEqualityComparer<;T>;,c#,.net,C#,.net,从MSDN的备注部分: 我们建议您从 EqualityComparer类而不是 实现IEqualityComparer 接口,因为 的EqualityComparer类测试 平等使用 IEquatable.Equals方法而不是 Object.Equals方法 我不理解引用的论点,即为什么我们更喜欢从EqualityComparer类派生,而不是实现IEqualityComparer。这意味着实现IEqualityComparer的对象将使用Object.Equals来测试相等性,但当我们不
- 我不理解引用的论点,即为什么我们更喜欢从
类派生,而不是实现EqualityComparer
。这意味着实现IEqualityComparer
的对象将使用IEqualityComparer
来测试相等性,但当我们不想使用Object.Equals
或Object.Equals
IEquatable.Equals来测试相等性时,实现
的目的不是全部吗IEqualityComparer
- 它还意味着,如果我们从
派生,那么派生类将使用EqualityComparer
方法测试相等性。同样,当我们不想使用IEquatable.Equals
或Object.Equals
IEquatable.Equals来测试相等性时,从
派生的全部要点难道不是吗(因为EqualityComparer
已经使用EqualityComparer.Default
或Object.Equals
)IEquatable.Equals
- 我通过调用
或IEquatable.Equals
(取决于类型为Object.Equals
的元素是否实现T
)通过IEquatable
EqualityComparer.Default
- 为什么这些集合(在测试默认相等性时)不直接调用
或IEquatable.Equals
而不是通过Object.Equals
类EqualityComparer.default
我不明白你给我的建议。我觉得这很奇怪
至于2,通常情况下,你会得到一个类型(比如
字典
)它有一个IEqualityComparer
。虽然实现可以存储一个空值并显式调用Equals
本身,但这样做将是一件痛苦的事情,而且还将涉及到非常丑陋的事情,以确保它不会不必要地将实现IEquatable
的值类型装箱tyComparer.Default非常简单且更加一致。关于您的第一个问题:
该类的备注部分似乎并没有真正提供为什么您更喜欢从抽象类派生而不是从接口派生的原因,它听起来更像是一个为什么首先存在equality comparer接口的原因。它所说的实际上是无用的,它基本上描述了默认实现如果有什么区别的话,他们在这里提供的“推理”听起来更像是你的比较器可以做什么的指南,与它实际做什么无关
查看EqualityComparer
类的公共/受保护接口,只有一个补救性质,它实现了非泛型IEqualityComparer
接口。我认为他们的意思是,他们建议从中派生,因为EqualityComparer
实际上实现了非泛型IEqualityComparer
接口,这样您的类就可以在需要非泛型比较器的地方使用
在备注一节中,它确实更有意义,因为:
我们建议您从Comparer
类派生,而不是实现IComparer
接口,因为Comparer
类提供了IComparer.Compare
方法和获取对象默认比较器的Default
属性的显式接口实现。
我怀疑它应该对IEqualityComparer
说一些类似的话,但有些想法被混淆了,最终导致描述不完整
关于你的第二个问题: 在库中找到的集合的一个主要目标是尽可能灵活。实现这一目标的一种方法是,通过提供
IComparer
或IEqualityComparer
来进行比较,从而允许自定义方式来比较其中的对象。当一个这些比较器可以包含调用适当的比较所需的逻辑
e、 例如,默认比较器可以确定T
是否在对象上实现IEquatable
并调用IEquatable.Equals
,或者使用object.Equals
。在比较器中封装比在集合代码中重复更好
此外,如果他们想退回到直接调用IEquatable.Equals
,他们必须在T
上添加一个约束,这将使调用成为可能。这样做会降低灵活性,并否定首先提供比较器的好处
从基类派生类的主要原因是
类可以提供您可以重用的代码,所以您不必编写它
你自己
如果要从接口派生比较器,则必须创建
为您自己提供默认比较器的代码(当然,只有在您需要它的情况下,但是大家都想要免费的功能!)
类使用
在Factory模式中,我们创建对象而不使用expo
class DictionaryComparerFactory<TKey, TValue> :
EqualitiyComparer<Dictionary<TKey, TValue>>
{
// By deriving from EqaulityComparer, you already have comparer (1)
// via property Default
// comparer (4):
// X and Y are equal if equal keys and equal values using provided value comparer
public static IEqualityComparer<Dictionary<TKey, TValue>>
CreateContentComparer(IEqualityComparer<TValue> valueComparer)
{
return new DictionaryComparer<TKey, TValue>(valueComparer);
}
// comparer (3): X and Y equal if equal keys and values default equal
// use (4) by providing the default TValue comparer
public static IEqualityComparer<Dictionary<TKey, TValue>>
CreateDefaultValueComparer(IEqualityComparer<TValue> valueComparer)
{
IEqualityComparer<TValue> defaultValueComparer =
EqualtiyComparer<TValue>.Default;
return new DictionaryComparer<TKey, TValue>(defaultValuecomparer);
}
// comparer (2): X and Y are equal if equal keys and values are same object
// use reference equal for values
public IEqualityComparer<TKey, TValue> CreateReferenceValueComparer()
{
IEqualityComparer<TValue> referenceValueComparer = ...
return new DictionaryComparer<TKey, TValue>(referenceValuecomparer);
}
}
// constructor
protected DictionaryComparer(IEqualityComparer<TValue> valueComparer) : base()
{ // if no comparer provided, use the default comparer
if (Object.ReferenceEquals(valueComparer, null))
this.valueComparer = EqualityComparer<TValue>.Default;
else
this.valueComparer = valueComparer
}
// comparer for TValue initialized in constructor
protected readonly IEqualityComparer<TValue> valueComparer;
public override bool Equals(Dictionary<TKey, TValue> x, Dictionary<TKey, TValue> y)
{
if (x == null) { return y == null; }
if (y == null) return false;
if (Object.ReferenceEquals(x, y)) return true;
if (x.GetType() != y.GetType()) return false;
// now do equality checks according to (4)
foreach (KeyValuePair<TKey, TValue> xKeyValuePair in x)
{
TValue yValue;
if (y.TryGetValue(xKeyValuePair.Key, out yValue))
{ // y also has x.Key. Are values equal?
if (!this.valueComparer.Equals(xKeyValuePair.Value, yValue))
{ // values are not equal
return false;
}
// else: values equal, continue with next key
}
else
{ // y misses a key that is in x
return false;
}
}
// if here, all key/values equal
return true;
}
var dictionaryX = ...
var dictionaryY = ...
var valueComparer1 = ...
var valueComparer2 = ...
var equalityComparer1 = DictionaryComparer<...>.Default();
var equalityComparer2 = DictionaryComparer<...>..CreateDefaultValueComparer();
var equalityComparer3 = DictionaryComparer<...>.CreatereferenceValueComparer();
var equalityComparer4 = DictionaryComparer<...>
.CreateContentComparer(valueCompaerer1);
var equalityComparer5 = DictionaryComparer<...>
.CreateContentComparer(valueCompaerer2);