type number generic convert cast c# equality boxing unboxing

c# - number - Comparación de tipos de valores en caja



type number c# (5)

Hoy me encontré con un error interesante que escribí. Tengo un conjunto de propiedades que se pueden establecer a través de un setter general. Estas propiedades pueden ser tipos de valores o tipos de referencia.

public void SetValue( TEnum property, object value ) { if ( _properties[ property ] != value ) { // Only come here when the new value is different. } }

Al escribir una prueba unitaria para este método, descubrí que la condición es siempre cierta para los tipos de valores. No me llevó mucho tiempo darme cuenta de que esto se debe al boxing/unboxing . Tampoco me llevó mucho tiempo ajustar el código a lo siguiente:

public void SetValue( TEnum property, object value ) { if ( !_properties[ property ].Equals( value ) ) { // Only come here when the new value is different. } }

La cuestión es que no estoy del todo satisfecho con esta solución. Me gustaría mantener una comparación de referencia simple, a menos que el valor esté enmarcado.

La solución actual en la que estoy pensando solo llama a Equals() para los valores encasillados. Hacer un control de los valores enmarcados parece un poco exagerado. ¿No hay una manera más fácil?


Como el tipo de parámetro de entrada es un object , siempre obtendrá un valor encuadrado dentro del contexto del método.

Creo que tu única posibilidad es cambiar la firma del método y escribir sobrecargas diferentes.


Equals () es generalmente el enfoque preferido.

La implementación predeterminada de .Equals () hace una comparación de referencia simple para los tipos de referencia, por lo que en la mayoría de los casos eso es lo que obtendrás. Equals () podría haber sido reemplazado para proporcionar algún otro comportamiento, pero si alguien ha anulado .Equals () en una clase es porque quiere cambiar la semántica de igualdad para ese tipo, y es mejor dejar que eso suceda si no lo hace tener una razón convincente para no hacerlo. Superarlo usando == puede generar confusión cuando su clase ve dos cosas diferentes cuando cada clase acepta que son iguales.


Qué tal esto:

if(object.ReferenceEquals(first, second)) { return; } if(first.Equals(second)) { return; } // they must differ, right?

Actualizar

Me di cuenta de que esto no funciona como se esperaba para un caso determinado:

  • Para los tipos de valor, ReferenceEquals devuelve falso, por lo que recurrimos a Equals , que se comporta como se esperaba.
  • Para los tipos de referencia donde ReferenceEquals devuelve verdadero, los consideramos "iguales" como se esperaba.
  • Para los tipos de referencia donde ReferenceEquals devuelve false e Equals devuelve false, los consideramos "diferentes" como se esperaba.
  • Para los tipos de referencia donde ReferenceEquals devuelve false e Equals devuelve true, los consideramos "iguales" aunque deseemos "different"

Entonces la lección es "no seas listo"


Si necesita un comportamiento diferente cuando se trata de un tipo de valor, obviamente tendrá que realizar algún tipo de prueba. No necesita una comprobación explícita para los tipos de valores encuadrados, ya que todos los tipos de valores se guardarán en recuadro ** debido al parámetro que se escribe como object .

Este código debe cumplir con los criterios establecidos: si el value es un tipo de valor (en recuadro), llame al método polimórfico Equals , de lo contrario use == para probar la igualdad de referencia.

public void SetValue(TEnum property, object value) { bool equal = ((value != null) && value.GetType().IsValueType) ? value.Equals(_properties[property]) : (value == _properties[property]); if (!equal) { // Only come here when the new value is different. } }

(** Y, sí, sé que Nullable<T> es un tipo de valor con sus propias reglas especiales relacionadas con el boxeo y el desempaquetado, pero eso es bastante irrelevante aquí).


supongo

Me gustaría mantener una comparación de referencia simple, a menos que el valor esté enmarcado.

es algo equivalente a

Si el valor está enmarcado, haré una comparación de referencia no "simple".

Esto significa que lo primero que deberá hacer es verificar si el valor está encasillado o no.

Si existe un método para verificar si un objeto es un tipo de valor encuadrado o no, debe ser al menos tan complejo como el método de "exageración" al que proporcionó el enlace a menos que no sea la manera más simple. No obstante, debe haber una "forma más simple" de determinar si un objeto es un tipo de valor encuadrado o no. Es poco probable que esta "forma más simple" sea más simple que simplemente usar el método Equals () del objeto, pero he marcado esta pregunta para averiguarlo por si acaso.

(no estoy seguro de si era lógico)