Estoy escribiendo un contenedor para elementos XML que permite a un desarrollador analizar fácilmente los atributos del XML. El contenedor no tiene otro estado que el objeto que se está envolviendo.
Estoy considerando la siguiente implementación (simplificada para este ejemplo) que incluye una sobrecarga para el ==
operador.
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);
}
}
Según entiendo idiomatic c #, el ==
operador es para la igualdad de referencia, mientras que el Equals()
método es para la igualdad de valores. Pero en este caso, el "valor" es solo una referencia al objeto que se está envolviendo. Por lo tanto, no tengo claro qué es convencional o idiomático para c #.
Por ejemplo, en este código ...
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.");
}
.... ¿debería el programa generar "Los contenedores a y b son iguales"? ¿O sería extraño, es decir, violar el principio de menor asombro ?
Equals
, nunca superé==
(pero nunca al revés). ¿Es perezoso idiomático? Si obtengo un comportamiento diferente sin un reparto explícito que viola menos asombro.Respuestas:
Dado que la referencia a la envoltura
XElement
es inmutable, no hay una diferencia externamente observable entre dos instancias deXmlWrapper
esa envoltura del mismo elemento, por lo que tiene sentido sobrecargar==
para reflejar este hecho.El código del cliente casi siempre se preocupa por la igualdad lógica (que, de forma predeterminada, se implementa utilizando la igualdad de referencia para los tipos de referencia). El hecho de que haya dos instancias en el montón es un detalle de implementación que a los clientes no debería importarles (y aquellos que sí usarán
Object.ReferenceEquals
directamente).fuente
Si crees que tiene más sentido
La pregunta y la respuesta dependen de las expectativas del desarrollador , no es un requisito técnico.
SI considera que un contenedor no tiene una identidad y se define únicamente por su contenido, la respuesta a su pregunta es sí.
Pero este es un problema recurrente. ¿Deberían dos envoltorios exhibir igualdad cuando envuelven objetos diferentes pero con ambos objetos que tienen exactamente el mismo contenido?
La respuesta se repite. SI los objetos de contenido no tienen identidad personal y en su lugar están puramente definidos por su contenido, entonces los objetos de contenido son envoltorios que exhibirán igualdad. Si luego envuelve los objetos de contenido en otro contenedor, ese contenedor (adicional) también debería exhibir igualdad.
Son tortugas hasta el fondo .
Consejo general
Cada vez que se desvía del comportamiento predeterminado, debe documentarse explícitamente. Como desarrollador, espero que dos tipos de referencia no exhiban igualdad incluso si sus contenidos son iguales. Si cambia ese comportamiento, le sugiero que lo documente claramente para que todos los desarrolladores estén al tanto de este comportamiento atípico.
Ese es su comportamiento predeterminado, pero esta no es una regla inamovible. Es una cuestión de convención, pero las convenciones se pueden cambiar donde sea justificable .
string
es un gran ejemplo aquí, ya==
que también es una verificación de igualdad de valores (¡incluso cuando no hay internados de cadenas!) ¿Por qué? En pocas palabras: porque tener cadenas se comportan como objetos de valor se siente más intuitivo para la mayoría de los desarrolladores.Si su base de código (o la vida de sus desarrolladores) puede simplificarse notablemente haciendo que sus envoltorios exhiban igualdad de valor en todos los ámbitos, hágalo (pero documente ).
Si nunca necesita verificaciones de igualdad de referencia (o su dominio comercial las vuelve inútiles), entonces no tiene sentido mantener una verificación de igualdad de referencia. Es mejor reemplazarlo con una verificación de igualdad de valores para evitar errores de desarrollador .
Sin embargo, tenga en cuenta que si necesita verificaciones de igualdad de referencia más adelante, volver a implementarlo puede requerir un esfuerzo notable.
fuente
==
verifica la igualdad de referencia, ya que este es el comportamiento predeterminado. Sin embargo, si==
realmente verifica la igualdad de valor, espero (es decir, requiero) que esto se documente explícitamente.I'm curious why you expect that reference types won't define content equality.
No lo definen por defecto , pero eso no significa que no se pueda hacer. Nunca dije que no se puede (o no se debe) hacer, simplemente no espero (es decir, asumo) por defecto.Básicamente, está comparando cadenas, por lo que me sorprendería que dos contenedores que contengan el mismo contenido XML no se consideren iguales, ya sea que se verifique con Equals o ==.
La regla idiomática puede tener sentido para los objetos de tipo de referencia en general, pero las cadenas son especiales en un sentido idiomático, se supone que debe tratarlas y considerarlas como valores, aunque técnicamente son tipos de referencia.
Sin embargo, su postfix Wrapper agrega confusión. Básicamente dice "no es un elemento XML". Entonces, ¿debería tratarlo como un tipo de referencia después de todo? Semánticamente esto no tendría sentido. Estaría menos confundido si la clase se llamara XmlContent. Esto indicaría que nos importa el contenido, no los detalles técnicos de implementación.
fuente