La principale raison de dériver une classe à partir d'une classe de base est que la base peut fournir du code que vous pouvez réutiliser, de sorte que vous n'avez pas à l'écrire vous-même. vous-même.
Si vous deviez dériver votre comparateur de l'interface, vous devriez créer le fichier qui vous donne un comparateur par défaut (bien sûr seulement si vous en avez besoin, mais bon, tout le monde veut une fonctionnalité gratuite !)
Classe EqualityComparer utilise le modèle de conception d'usine .
Dans le modèle Factory, nous créons un objet sans exposer la logique de création au client et nous faisons référence à l'objet nouvellement créé en utilisant une interface commune.
Ce qui est bien, c'est que tous les utilisateurs de EqualityComparer n'ont qu'à appeler prperty default, et tout est fait pour qu'ils créent l'objet approprié qui expose l'interface IEqualtiyComparer
L'avantage de cette méthode est que si vous avez besoin d'un IEqualityComparer comme paramètre dans une fonction, vous n'avez pas à vérifier si la classe T
met en œuvre IEqualtiy<T>
ou non, le dictionnaire le fait pour vous.
Si vous dérivez de EqualtityComparer<T>
et assurez-vous que la classe dérivée suit le modèle de conception de la fabrique. il est alors facile de passer d'un comparateur d'égalité à un autre.
En outre, comme pour toute usine, il suffit de modifier les paramètres de l'usine pour qu'elle produise des comparateurs d'égalité complètement différents.
Bien sûr, vous pouvez créer une usine de comparaison d'égalité sans dériver de EqualtyComparer<T>
mais si vous le faites, votre usine peut créer un type supplémentaire de comparateurs d'égalité : le comparateur d'égalité par défaut, qui est celui qui utilise eiether IEquatable<T>
ou Object.Equals. Vous n'avez pas besoin d'écrire de code supplémentaire pour cela, il suffit de dériver !
Que vous trouviez utile de dériver de EqualtyComparer ou non, dépend de l'utilité que vous accordez au modèle de conception "factory".
À titre d'exemple, supposons que vous souhaitiez vérifier l'égalité de deux dictionnaires. On peut imaginer plusieurs niveaux d'égalité :
- Les dictionnaires X et Y sont égaux s'ils sont le même objet.
- X et Y sont égaux s'ils ont des clés égales (en utilisant le comparateur de clés du dictionnaire), et si leurs valeurs sont le même objet.
- X et Y sont égaux s'ils ont des clés égales (en utilisant le comparateur de clés de dictionnaire), et si leurs valeurs sont égales en utilisant le comparateur d'égalité par défaut de l'option
TValue
- X et Y sont égaux s'ils ont des clés égales (en utilisant le comparateur de clés du dictionnaire), et des valeurs égales en utilisant un comparateur d'égalité fourni pour les valeurs.
Si vous dérivez votre classe de comparateur de dictionnaire de EqualityComparer, vous avez déjà le comparateur (1). Si le comparateur de valeurs TV fourni est dérivé de EqualityComparer, il n'y a pas de réelle différence entre (3) et (4).
Déterminons donc la fabrique qui peut créer ces quatre comparateurs :
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);
}
}
Pour le comparateur (2), vous pouvez utiliser le comparateur de valeurs de référence comme décrit dans stackoverflow. IEqualityComparer qui utilise ReferenceEquals
Nous avons donc maintenant quatre comparateurs d'égalité différents en ne fournissant le code que pour un seul comparateur. Le reste est réutilisé !
Cette réutilisation n'est pas aussi facile sans une usine qui crée des comparateurs par défaut.
Code pour le comparateur (4) : utiliser un comparateur fourni pour vérifier l'égalité pour TValue
// 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;
}
Maintenant, nous pouvons simplement comparer deux dictionnaires en utilisant des comparateurs différents :
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);
Ainsi, la dérivation fait que mes usines de comparaison d'égalité ont toujours un comparateur Defautlt approprié. Cela m'évite d'avoir à écrire le code moi-même
2 votes
Vous avez donné des citations, mais sans dire d'où elles venaient, ce qui rend plus difficile la compréhension du contexte...
3 votes
@Jon : D'ici : msdn.microsoft.com/fr/us/library/ms132123.aspx
4 votes
+1 pour la première question, je me souviens avoir lu cela dans les docs et ne pas l'avoir compris, mais je l'ai fait passer comme sans importance.
1 votes
Je m'excuse. Merci à Reed et BlueRaya d'avoir fourni le lien.