Ich schreibe einen Wrapper für XML-Elemente, mit dem ein Entwickler Attribute einfach aus dem XML-Code analysieren kann. Der Wrapper hat keinen anderen Status als das Objekt, das umbrochen wird.
Ich denke an die folgende Implementierung (vereinfacht für dieses Beispiel), die eine Überlastung für den ==
Bediener beinhaltet.
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);
}
}
Nach meinem Verständnis für C # dient der ==
Operator der Referenzgleichheit, während die Equals()
Methode der Wertgleichheit dient. In diesem Fall ist der "Wert" jedoch nur ein Verweis auf das Objekt, das umgebrochen wird. Mir ist also nicht klar, was für c # konventionell oder idiomatisch ist.
Zum Beispiel in diesem 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.");
}
.... sollte das Programm "Die Wrapper a und b sind gleich" ausgeben? Oder wäre das seltsam, das Prinzip des geringsten Erstaunens zu verletzen ?
Equals
ich nie==
(aber niemals umgekehrt). Ist faul idiomatisch? Wenn ich ein anderes Verhalten ohne eine explizite Besetzung bekomme, die am wenigsten gegen das Erstaunen verstößt.Antworten:
Da der Verweis auf die Umhüllung
XElement
unveränderlich ist, gibt es keinen äußerlich erkennbaren Unterschied zwischen zwei InstanzenXmlWrapper
dieser Umhüllung desselben Elements. Daher ist es sinnvoll, eine Überladung vorzunehmen==
, um diese Tatsache widerzuspiegeln.Client-Code kümmert sich fast immer um die logische Gleichheit (die standardmäßig unter Verwendung der Referenzgleichheit für Referenztypen implementiert wird). Die Tatsache, dass sich zwei Instanzen auf dem Heap befinden, ist ein Implementierungsdetail, das Clients nicht interessieren sollte (und die, die dies tun, werden es
Object.ReferenceEquals
direkt verwenden).quelle
Wenn Sie denken, dass es am sinnvollsten ist
Die Frage und Antwort ist eine Frage der Entwicklererwartung , dies ist keine technische Anforderung.
Wenn Sie der Meinung sind, dass ein Wrapper keine Identität hat und nur durch seinen Inhalt definiert ist, lautet die Antwort auf Ihre Frage Ja.
Dies ist jedoch ein immer wiederkehrendes Problem. Sollten zwei Wrapper gleich sein, wenn sie unterschiedliche Objekte umschließen, aber beide Objekte den exakt gleichen Inhalt haben?
Die Antwort wiederholt sich. Wenn die Inhaltsobjekte keine persönliche Identität haben und stattdessen nur durch ihren Inhalt definiert sind, sind die Inhaltsobjekte effektiv Wrapper, die Gleichheit aufweisen. Wenn Sie dann die Inhaltsobjekte in einen anderen Wrapper einwickeln, sollte dieser (zusätzliche) Wrapper ebenfalls Gleichheit aufweisen.
Es ist Schildkröten den ganzen Weg nach unten .
Allgemeiner Tipp
Wann immer Sie vom Standardverhalten abweichen, sollte dies explizit dokumentiert werden. Als Entwickler erwarte ich, dass zwei Referenztypen nicht gleich sind, auch wenn ihr Inhalt gleich ist. Wenn Sie dieses Verhalten ändern, sollten Sie es klar dokumentieren, damit alle Entwickler über dieses atypische Verhalten informiert sind.
Das ist das Standardverhalten, aber dies ist keine unbewegliche Regel. Es ist eine Frage der Konvention, aber Konventionen können geändert werden, wo dies gerechtfertigt ist .
string
ist hier ein großartiges Beispiel, ebenso wie==
eine Wertegleichheitsprüfung (auch wenn kein String interniert ist!). Warum? Einfach ausgedrückt: Da sich Strings wie Wertobjekte verhalten, fühlen sich die meisten Entwickler intuitiver an.Wenn sich Ihre Codebasis (oder das Leben Ihrer Entwickler) erheblich vereinfachen lässt, indem Ihre Wrapper auf ganzer Linie die gleiche Wertschätzung aufweisen, sollten Sie sie wählen (aber dokumentieren ).
Wenn Sie niemals Referenzgleichheitsprüfungen benötigen (oder diese von Ihrer Unternehmensdomäne unbrauchbar gemacht werden), ist es nicht sinnvoll, eine Referenzgleichheitsprüfung durchzuführen. Es ist besser, es durch eine Wertegleichheitsprüfung zu ersetzen, um Entwicklerfehler zu vermeiden .
Beachten Sie jedoch, dass die Neuimplementierung von Referenzgleichheitsprüfungen zu einem späteren Zeitpunkt einige Zeit in Anspruch nehmen kann.
quelle
==
auf Referenzgleichheit geprüft wird, da dies das Standardverhalten ist. Wenn jedoch==
tatsächlich auf Wertgleichheit geprüft wird, erwarte (dh erfordere) ich, dass dies explizit dokumentiert wird.I'm curious why you expect that reference types won't define content equality.
Sie definieren es nicht standardmäßig , aber das heißt nicht, dass es nicht möglich ist. Ich habe nie gesagt, dass dies nicht möglich ist (oder nicht möglich sein sollte), ich erwarte es einfach nicht (dh nehme es standardmäßig an).Sie vergleichen im Grunde Zeichenfolgen, und ich wäre erstaunt, wenn zwei Wrapper, die denselben XML-Inhalt enthalten, nicht als gleich angesehen würden, sei es mit Equals oder ==.
Die idiomatische Regel kann für Referenztypobjekte im Allgemeinen sinnvoll sein, aber Zeichenfolgen sind im idiomatischen Sinne besonders. Sie sollten sie behandeln und als Werte betrachten, obwohl es sich technisch gesehen um Referenztypen handelt.
Ihr Wrapper-Postfix sorgt jedoch für zusätzliche Verwirrung. Grundsätzlich heißt es "kein XML-Element". Soll ich es also doch als Referenztyp behandeln? Semantisch wäre dies nicht sinnvoll. Ich wäre weniger verwirrt, wenn die Klasse den Namen XmlContent hätte. Dies würde bedeuten, dass wir uns um Inhalte und nicht um Details der technischen Implementierung kümmern.
quelle