J'écris un wrapper pour les éléments XML qui permet à un développeur d'analyser facilement les attributs du XML. L'encapsuleur n'a aucun état autre que l'objet encapsulé.
J'envisage l'implémentation suivante (simplifiée pour cet exemple) qui inclut une surcharge pour l' ==
opérateur.
class XmlWrapper
{
protected readonly XElement _element;
public XmlWrapper(XElement element)
{
_element = element;
}
public string NameAttribute
{
get
{
//Get the value of the name attribute
}
set
{
//Set the value of the name attribute
}
}
public override bool Equals(object other)
{
var o = other as XmlWrapper;
if (o == null) return false;
return _element.Equals(o._element);
}
public override int GetHashCode()
{
return _element.GetHashCode();
}
static public bool operator == (XmlWrapper lhs, XmlWrapper rhs)
{
if (ReferenceEquals(lhs, null) && ReferenceEquals(rhs, null)) return true;
if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null)) return false;
return lhs._element == rhs._element;
}
static public bool operator != (XmlWrapper lhs, XmlWrapper rhs)
{
return !(lhs == rhs);
}
}
Si je comprends bien c # idiomatique, l' ==
opérateur est pour l'égalité de référence tandis que la Equals()
méthode est pour l'égalité des valeurs. Mais dans ce cas, la "valeur" n'est qu'une référence à l'objet encapsulé. Je ne sais donc pas ce qui est conventionnel ou idiomatique pour c #.
Par exemple, dans ce code ...
var underlyingElement = new XElement("Foo");
var a = new XmlWrapper(underlyingElement);
var b = new XmlWrapper(underlyingElement);
a.NameAttribute = "Hello";
b.NameAttribute = "World";
if (a == b)
{
Console.WriteLine("The wrappers a and b are the same.");
}
.... le programme devrait-il afficher "Les enveloppes a et b sont les mêmes"? Ou serait-ce étrange, c'est-à-dire violer le principe du moindre étonnement ?
Equals
je n'ai jamais dépassé==
(mais jamais l'inverse). Le paresseux est-il idiomatique? Si j'obtiens un comportement différent sans un casting explicite qui viole le moins d'étonnement.Réponses:
Étant donné que la référence à l'emballage
XElement
est immuable, il n'y a pas de différence observable extérieurement entre deux instances deXmlWrapper
cet emballage le même élément, il est donc logique de surcharger==
pour refléter ce fait.Le code client se soucie presque toujours de l'égalité logique (qui, par défaut, est implémentée en utilisant l'égalité de référence pour les types de référence). Le fait qu'il y ait deux instances sur le tas est un détail d'implémentation dont les clients ne devraient pas se soucier (et ceux qui le feront utiliser
Object.ReferenceEquals
directement).la source
Si vous pensez que cela a le plus de sens
La question et la réponse sont une question d' attente du développeur , ce n'est pas une exigence technique.
SI vous considérez qu'un wrapper n'a pas d'identité et qu'il doit être défini uniquement par son contenu, alors la réponse à votre question est oui.
Mais c'est un problème récurrent. Deux wrappers doivent-ils montrer l'égalité lorsqu'ils enveloppent des objets différents mais avec les deux objets ayant exactement le même contenu?
La réponse se répète. SI les objets de contenu n'ont pas d'identité personnelle et sont plutôt purement définis par leur contenu, alors les objets de contenu sont en fait des wrappers qui présenteront l'égalité. Si vous encapsulez ensuite les objets de contenu dans un autre wrapper, ce wrapper (supplémentaire) doit alors également présenter l'égalité.
C'est des tortues tout le long .
Conseil général
Chaque fois que vous vous écartez du comportement par défaut, cela devrait être explicitement documenté. En tant que développeur, je m'attends à ce que deux types de référence ne présentent pas l'égalité même si leur contenu est égal. Si vous changez ce comportement, je vous suggère de le documenter clairement afin que tous les développeurs soient conscients de ce comportement atypique.
C'est son comportement par défaut, mais ce n'est pas une règle inamovible. C'est une question de convention, mais les conventions peuvent être modifiées lorsque cela se justifie .
string
est un excellent exemple ici, tout comme==
un contrôle d'égalité de valeur (même lorsqu'il n'y a pas de chaîne interne!). Pourquoi? En termes simples: car avoir des chaînes se comportent comme des objets de valeur semble plus intuitif pour la plupart des développeurs.Si votre base de code (ou la vie de vos développeurs) peut être considérablement simplifiée en faisant en sorte que vos wrappers présentent une égalité de valeur à tous les niveaux, allez-y (mais documentez-le ).
Si vous n'avez jamais besoin de vérifications d'égalité de référence (ou qu'elles sont rendues inutiles par votre domaine d'activité), il est inutile de conserver une vérification d'égalité de référence. Il est préférable de le remplacer par une vérification d'égalité des valeurs afin d' éviter les erreurs de développeur .
Cependant, sachez que si vous avez besoin de vérifications d'égalité de référence plus tard, la réimplémentation peut prendre un effort notable.
la source
==
vérifie l'égalité de référence car c'est le comportement par défaut. Cependant, si==
vérifie réellement l'égalité des valeurs, je m'attends (c'est-à-dire exige) que cela soit documenté explicitement.I'm curious why you expect that reference types won't define content equality.
Ils ne le définissent pas par défaut , mais cela ne signifie pas que cela ne peut pas être fait. Je n'ai jamais dit que cela ne pouvait pas (ou ne devait pas) être fait, je ne m'y attendais pas (c'est-à-dire l'assumais) par défaut.Vous comparez essentiellement des chaînes, donc je serais étonné que deux wrappers contenant le même contenu XML ne soient pas considérés comme égaux, que ce soit vérifié en utilisant Equals ou ==.
La règle idiomatique peut avoir un sens pour les objets de type référence en général, mais les chaînes sont spéciales dans un sens idiomatique, vous êtes censé les traiter et les considérer comme des valeurs bien que techniquement ce soient des types de référence.
Votre postfixe Wrapper ajoute cependant de la confusion. Il dit essentiellement "pas un élément XML". Dois-je donc le traiter comme un type de référence après tout? Sémantiquement, cela n'aurait aucun sens. Je serais moins confus si la classe était nommée XmlContent. Cela signifierait que nous nous soucions du contenu, et non des détails techniques de mise en œuvre.
la source