Question

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 mon MyClass<T> a un constructeur qui prend en charge le passage d'une coutume IEqualityComparer<T>, semblable à Dictionary<T>. Dans ce cas, j'aurais besoin de 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 déclaration, ce serait bien si je pouvais avoir _comparer par défaut à un «comparateur par défaut» si le constructeur régulier est utilisé. J'ai cherché quelque chose comme typeof(T).GetDefaultComparer() Mais n'a pas pu trouver quelque chose de tel.

J'ai trouvé EqualityComparer<T>.Default, pourrais-je utiliser ça? Et alors 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 o1.Equals(o2) pour tous les cas possibles?

(En tant que note secondaire, cela signifierait-il également que je devrais également utiliser toute contrainte générique spéciale pour <T>?)

Était-ce utile?

La solution

Cela devrait être identique, mais il n'est pas garanti, car cela dépend des détails de l'implémentation du type T.
Explication:
Sans contrainte à T, o1.equals (o2) appellera Object.Equals, même si T met en oeuvre IEquatable<T>.
EqualityComparer<T>.Default Cependant, vous utilisera Object.Equals seulement si T ne met pas en œuvre IEquatable<T>. Si ça Est-ce que implémenter cette interface, il utilise IEquatable<T>.Equals.
Aussi longtemps que Tla mise en œuvre de Object.Equals les appels justes IEquatable<T>.Equals le résultat est le même. Mais dans l'exemple suivant, le résultat n'est pas le même:

public class MyObject : IEquatable<MyObject>
{
    public int ID {get;set;}
    public string Name {get;set;}

    public override bool Equals(object o)
    {
        var other = o as MyObject;
        return other == null ? false : other.ID == ID;
    }    

    public bool Equals(MyObject o)
    {
        return o.Name == Name;
    } 
}

Maintenant, il n'a aucun sens d'implémenter une classe comme celle-ci. Mais vous aurez le même problème, si l'ex-implémentateur de MyObject J'ai simplement oublié de remplacer Object.Equals.

Conclusion:
Utilisant EqualityComparer<T>.Default est une bonne façon de procéder, car vous n'avez pas besoin de prendre en charge les objets buggy!

Autres conseils

Par défaut, jusqu'à dépasser dans une classe, Object.Equals(a,b)/a.Equals(b) Effectue une comparaison par référence.

Quel comparateur sera retourné par EqualityComparer<T>.Default dépend de T. Par exemple, si T : IEquatable<> alors le approprié EqualityComparer<T> sera créé.

Vous pouvez utiliser l'opérateur coaelescense nul ?? Pour raccourcir le si c'est vraiment important

  if ((_comparer ?? EqualityComparer<T>.Default).Equals(o1, o2))
  {

  }

Oui, je pense qu'il serait sage d'utiliser le EqualityComparer<T>.Default, parce qu'il utilise la mise en œuvre de IEquatable<T> Si le type T L'implémente, ou le remplacement de Object.Equals Par ailleurs. Vous pouvez le faire comme suit:

private IEqualityComparer<T> _comparer;
public IEqualityComparer<T> Comparer
{
    get { return _comparer?? EqualityComparer<T>.Default;}
    set { _comparer=value;}
}
public MyClass(IEqualityComparer<T> comparer)
{  
    _comparer = comparer;
}
void DoSomething(T o1, T o2)
{  
    if(Comparer.Equals(o1, o2))
    {
     ...
    }
}

C'est exactement ce Dictionary<> et d'autres collections génériques dans le BCL font si vous ne spécifiez pas de comparateur lors de la construction de l'objet. L'avantage de cela est que EqualityComparer<T>.Default retournera le bon comparateur pour IEquatable<T> types, types nullables et énumérations. Si T n'est rien de ceux-ci, il fera une comparaison égale simple comme vous le faites Old Code.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top