从基类派生类的主要原因是,基类可以提供可重用的代码,这样您就不必自己编写它。
如果您从接口派生比较器,则必须自己创建给您提供默认比较器的代码(当然,只有在需要时才需要,但嘿,每个人都想要免费功能!)。
类EqualityComparer使用工厂设计模式。
在工厂模式中,我们创建对象而不将创建逻辑暴露给客户端,并使用公共接口引用新创建的对象。
好处是所有EqualityComparer的用户只需调用属性default,一切都为他们完成,以创建公开接口IEqualtiyComparer的正确对象。
这样做的好处是,如果您需要将IEqualityComparer作为函数参数,则无需检查类T
是否实现了IEqualtiy<T>
,因为Dictionary会为您执行此操作。
如果您从EqualtityComparer<T>
派生并确保派生类遵循工厂设计模式,那么在几个相等比较器之间切换就很容易。
此外,与任何工厂一样,您只需更改工厂的参数即可让其生成完全不同的相等比较器。
当然,您可以创建一个相等比较器工厂而不从EqualtyComparer<T>
派生,但如果您确实派生,则您的工厂可以创建一种额外类型的相等比较器:默认相等比较器,它是使用IEquatable<T>
或Object.Equals的比较器。您不必为此编写任何额外的代码,只需派生即可!
是否有用从EqualtyComparer派生还是取决于您是否认为工厂设计模式有用。
举个例子,假设你想要检查两个字典是否相等。可以考虑几个不同程度的相等性:
- 如果字典 X 和 Y 是同一个对象,它们就是相等的
- X 和 Y 相等,如果它们具有相等的键(使用字典键比较器),并且它们的值是同一个对象
- X 和 Y 相等,如果它们具有相等的键(使用字典键比较器),并且它们的值使用
TValue
的默认相等比较器是相等的
- X 和 Y 相等,如果它们具有相等的键(使用字典键比较器),并且它们的值使用提供的值相等比较器是相等的。
如果你从EqualityComparer类派生你的字典比较器类,你已经拥有了比较器(1)。如果提供的TValue比较器是从EqualityComparer派生的,则(3)和(4)之间没有实际区别。
因此,让我们来推导一下可以创建这四个比较器的工厂:
class DictionaryComparerFactory<TKey, TValue> :
EqualitiyComparer<Dictionary<TKey, TValue>>
{
public static IEqualityComparer<Dictionary<TKey, TValue>>
CreateContentComparer(IEqualityComparer<TValue> valueComparer)
{
return new DictionaryComparer<TKey, TValue>(valueComparer);
}
public static IEqualityComparer<Dictionary<TKey, TValue>>
CreateDefaultValueComparer(IEqualityComparer<TValue> valueComparer)
{
IEqualityComparer<TValue> defaultValueComparer =
EqualtiyComparer<TValue>.Default;
return new DictionaryComparer<TKey, TValue>(defaultValuecomparer);
}
public IEqualityComparer<TKey, TValue> CreateReferenceValueComparer()
{
IEqualityComparer<TValue> referenceValueComparer = ...
return new DictionaryComparer<TKey, TValue>(referenceValuecomparer);
}
}
关于比较器(2),您可以使用在stackoverflow中描述的使用ReferenceEquals的IEqualityComparer作为参考值比较器
现在我们只需提供一个比较器的代码,就有了四个不同的相等性比较器!其余部分被重复使用!
如果没有创建默认比较器的工厂,这种重用就不那么容易。
比较器(4)的代码:使用提供的比较器检查TValue的相等性。
protected DictionaryComparer(IEqualityComparer<TValue> valueComparer) : base()
{
if (Object.ReferenceEquals(valueComparer, null))
this.valueComparer = EqualityComparer<TValue>.Default;
else
this.valueComparer = valueComparer
}
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;
foreach (KeyValuePair<TKey, TValue> xKeyValuePair in x)
{
TValue yValue;
if (y.TryGetValue(xKeyValuePair.Key, out yValue))
{
if (!this.valueComparer.Equals(xKeyValuePair.Value, yValue))
{
return false;
}
}
else
{
return false;
}
}
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);
因此,派生使得我的相等比较器工厂始终具有适当的默认比较器。这样可以避免我自己编写代码。