suma reales racionales propiedades numeros negativos naturales los historia enteros c# .net

c# - reales - propiedades de los numeros enteros



¿Por qué el cero entero no es igual a cero largo? (6)

Un código extraño que acabo de descubrir en C # (también debería ser válido para otros lenguajes CLI utilizando las structs de .NET).

using System; public class Program { public static void Main(string[] args) { int a; long b; a = 0; b = 0; Console.WriteLine(a.Equals(b)); // False Console.WriteLine(a.Equals(0L)); // False Console.WriteLine(a.Equals((long)0)); // False Console.WriteLine(a.Equals(0)); // True Console.WriteLine(a.Equals(a)); // True Console.WriteLine(a == b); // True Console.WriteLine(a == 0L); // True Console.WriteLine(); Console.WriteLine(b.Equals(a)); // True Console.WriteLine(b.Equals(0)); // True Console.WriteLine(b.Equals((int)0)); // True Console.WriteLine(b.Equals(b)); // True Console.WriteLine(b == a); // True Console.WriteLine(b == 0); // True } }

Dos puntos interesantes aquí (suponiendo que a es int y b es long ):

  1. a != b , pero b == a ;
  2. (a.Equals(b)) != (a == b)

¿Hay alguna razón por la cual la comparación fue implementada de esta manera?

Nota: se usó .NET 4 si hay alguna diferencia.


C # no hace casting automático. La función de igual compara tipos y valores. Al igual que === en JS.


En general, no se supone que los métodos Equals() devuelvan verdadero para objetos de diferentes tipos.

a.Equals(b) llama a int.Equals(object) , que solo puede devolver true para Int32 s en caja:

public override bool Equals(Object obj) { if (!(obj is Int32)) { return false; } return m_value == ((Int32)obj).m_value; }

b.Equals(a) llama a long.Equals(long) después de convertir implícitamente el int en un long .
Por lo tanto, compara los dos long s directamente, volviendo verdadero.

Para entender más claramente, mire la IL generada por este ejemplo más simple (que imprime Verdadero Falso Verdadero):

int a = 0; long b = 0L; Console.WriteLine(a == b); Console.WriteLine(a.Equals(b)); Console.WriteLine(b.Equals(a));

IL_0000: ldc.i4.0 IL_0001: stloc.0 IL_0002: ldc.i4.0 IL_0003: conv.i8 IL_0004: stloc.1 IL_0005: ldloc.0 //Load a IL_0006: conv.i8 //Cast to long IL_0007: ldloc.1 //Load b IL_0008: ceq //Native long equality check IL_000A: call System.Console.WriteLine //True IL_000F: ldloca.s 00 //Load the address of a to call a method on it IL_0011: ldloc.1 //Load b IL_0012: box System.Int64 //Box b to an Int64 Reference IL_0017: call System.Int32.Equals IL_001C: call System.Console.WriteLine //False IL_0021: ldloca.s 01 //Load the address of b to call a method on it IL_0023: ldloc.0 //Load a IL_0024: conv.i8 //Convert a to Int64 IL_0025: call System.Int64.Equals IL_002A: call System.Console.WriteLine //True


Las sobrecargas de operadores y métodos, así como los operadores de conversión, se evalúan en el momento de la compilación, a diferencia de las modificaciones del método virtual que se evalúan en tiempo de ejecución. La expresión someIntVar.Equals(someNumericQuantity) tiene someIntVar.Equals(someNumericQuantity) relación con la expresión someObjectVarThatHoldsAnInt.Equals(someNumericQuantity) . Si pretendiera que el método virtual Object.Equals tiene un nombre diferente (como IsEquivalentTo ), y sustituya ese nombre en cada lugar donde se usa el método virtual, esto sería mucho más claro. Un cero entero puede ser numéricamente igual a un cero largo, pero eso no significa que sean semánticamente equivalentes.

Tal separación en el significado entre Equals e IsEquivalentTo , incidentalmente, también habría ayudado a evitar la confusión en la definición de este último. Es posible definir una relación de equivalencia significativa para objetos arbitrarios: la ubicación de almacenamiento X debe considerarse equivalente a la ubicación de almacenamiento Y si el comportamiento de todos los miembros de la primera siempre será equivalente a los miembros correspondientes de la última, y ​​la única manera de determinar si X e Y refieren al mismo objeto sería usar Reflection o ReferenceEquals . Aunque 1.0m.Equals(1.00m) es y debería ser cierto, 1.0m.IsEquivalentTo(1.00m) debe ser falso. Desafortunadamente, el uso del mismo nombre para el método de prueba de equivalencia de objetos y el método de prueba de igualdad numérica Decimal llevó a Microsoft a definir que el primero se comporte como el último.


No son lo mismo porque incluso los tipos simples se heredan de System.Object: en realidad son objetos y los diferentes tipos de objetos, incluso con los mismos valores de propiedad, no son iguales.

Ejemplo:

Podría tener un objeto Colaborador con una sola propiedad: Nombre (cadena) y un objeto asociado con una sola propiedad: Nombre (cadena)

El compañero de trabajo David no es lo mismo que Parner David. El hecho de que sean tipos de objetos diferentes los distingue.

En su caso, utilizando .Equals (), no está comparando valores, está comparando objetos. El objeto no es "0", es un System.Int32 con un valor de cero y un System.Int64 con un valor de cero.

Ejemplo de código basado en la pregunta en el comentario a continuación:

class CoWorker { public string Name { get; set; } } class Partner { public string Name { get; set; } } private void button1_Click(object sender, RoutedEventArgs e) { CoWorker cw = new CoWorker(); cw.Name = "David Stratton"; Partner p = new Partner(); p.Name = "David Stratton"; label1.Content = cw.Equals(p).ToString(); // sets the Content to "false" }


También está el problema de reducir o ampliar la conversión. Un cero long siempre es igual a un cero int , pero no al revés.

Cuando se compara un largo con un int, solo se comparan los 32 bits menos significativos y se ignora el resto, por lo que la int.Equals(long) no puede garantizar la igualdad incluso si los bits más bajos coinciden.

int a = 0; long b = 0; Trace.Assert(a.Equals((int)b)); // True 32bits compared to 32bits Trace.Assert(a.Equals((long)b)); // False 32bits compared to 64bits (widening) Trace.Assert(b.Equals((long)a)); // True 64bits compared to 64bits Trace.Assert(b.Equals((int)a)); // True 64bits compared to 32bits (narrowing)

También considere el caso donde los 32 bits inferiores son iguales, pero los superiores no lo son.

uint a = 0; ulong b = 0xFFFFFF000000; Trace.Assert((uint)a == (uint)b);  // true because of a narrowing conversion Trace.Assert((ulong)a == (ulong)b);  // false because of a widening conversion