EqualityComparer<T>.Par défaut contre T. est Égal à
Supposons que j'ai un générique MyClass<T>
qui doit comparer deux objets de type <T>
. Habituellement, je ferais quelque chose comme ...
void DoSomething(T o1, T o2)
{
if(o1.Equals(o2))
{
...
}
}
Supposons maintenant que mon MyClass<T>
a un constructeur qui prend en charge le passage d'un personnalisé IEqualityComparer<T>
, semblable à Dictionnaire<T>
. Dans ce cas, j'avais besoin de le faire ...
private IEqualityComparer<T> _comparer;
public MyClass() {}
public MyClass(IEqualityComparer<T> comparer)
{
_comparer = comparer;
}
void DoSomething(T o1, T o2)
{
if((_comparer != null && _comparer.Equals(o1, o2)) || (o1.Equals(o2)))
{
...
}
}
Pour supprimer cette longue si l'instruction, ce serait bien si je pouvais avoir _comparer
par défaut à un "comparateur par défaut" si la régulière constructeur est utilisé. J'ai cherché quelque chose comme typeof(T).GetDefaultComparer()
, mais n'était pas en mesure de trouver quelque chose comme ça.
Je n'ai trouver EqualityComparer<T>.Default
, pourrais-je l'utiliser? Puis cet extrait ...
public MyClass()
{
_comparer = EqualityComparer<T>.Default;
}
void DoSomething(T o1, T o2)
{
if(_comparer.Equals(o1, o2))
{
...
}
}
... fournir les mêmes résultats que l'utilisation de o1.Equals(o2)
pour tous les cas possibles?
(Comme une note de côté, serait-ce à dire que j'avais aussi besoin d'utiliser toute spéciale contrainte générique pour <T>
?)
- Remarque: Si
o1
est null,o1.Equals(o2)
échoue à l'omniprésence de laNullReferenceException
, alors queEqualityComparer<T>.Default.Equals(o1, o2)
sera heureux de retourner false. - C'est pourquoi j'ai dit "j'aimerais faire quelque chose comme ...", et pas "Voici mon code de production ..." 😉
Vous devez vous connecter pour publier un commentaire.
Il devrait être le même, mais il n'est pas garanti, car il dépend des détails de mise en œuvre de la type
T
.Explication:
Sans contrainte de
T
, o1.Equals(o2) va appelerObject.Equals
, même siT
implémenteIEquatable<T>
.EqualityComparer<T>.Default
cependant, va utiliserObject.Equals
seulement, siT
ne pas mettre en œuvreIEquatable<T>
. Si il ne à implémenter cette interface, il utiliseIEquatable<T>.Equals
.Aussi longtemps que
T
's la mise en œuvre deObject.Equals
appelle justeIEquatable<T>.Equals
le résultat est le même. Mais dans l'exemple suivant, le résultat n'est pas le même:Maintenant, il ne ferait aucun sens de mettre en œuvre une classe de ce genre. Mais vous avez le même problème, si le responsable de l'implémentation de
MyObject
tout simplement oublié de remplacerObject.Equals
.Conclusion:
À l'aide de
EqualityComparer<T>.Default
est une bonne façon d'aller, parce que vous n'avez pas besoin de soutien buggy objets!public MyClass<T> where T : IEquatable<T>
ensuite. Bon, vous avez tous été extrêmement utile.return other != null && other.ID == ID;
object.Equals
mise en œuvre commeDependencyObject
. Dans ces cas, il est super important d'utiliserEqualityComparer<T>.Default
à assurez-vous que votre propre mise en œuvre deEquals
est appelé.Par défaut, jusqu'à ce que redéfinie dans une classe,
Object.Equals(a,b)
/a.Equals(b)
effectue par comparaison de référence.Comparer ce sera retourné par la
EqualityComparer<T>.Default
dépendT
. Par exemple, siT : IEquatable<>
puis leEqualityComparer<T>
sera créé.Vous pouvez utiliser la valeur null coaelescense opérateur ?? pour raccourcir le si si c'est vraiment des questions
Oui, je pense qu'il serait sage d'utiliser le
EqualityComparer<T>.Default
, car il utilise la mise en œuvre deIEquatable<T>
si le typeT
la met en œuvre, ou le remplacement deObject.Equals
autrement. Vous pourriez le faire comme suit:C'est exactement ce que
Dictionary<>
et d'autres génériques collections de la BCL faire si vous ne spécifiez pas un comparateur lors de la construction de l'objet. L'avantage de ceci est queEqualityComparer<T>.Default
sera de retour le droit de comparer pourIEquatable<T>
types, les types nullables, et les énumérations. Si T est aucun de ceux-ci, il va faire une simple comparaison est Égal à, comme vous êtes vieux code est fait.