c# - operator - Sobrecarga del operador post-incremento
custom operator c# (3)
La clave está en entender cómo la línea Account b = a++;
trabajos. Dado cómo se escribe tu código, esta línea es el equivalente de esto:
Account b = a;
a++;
Y ese es el orden en el que se ejecutará. La asignación (1) ocurre efectivamente antes del incremento. Entonces, el primer efecto de esta línea es que ayb se refieren al objeto original a .
Ahora se evaluará la parte ++. Dentro del método del operador, incrementamos el Balance
del objeto original. En este punto, a y b apuntan al original, con un Balance
de 11, y b continuará haciéndolo.
Sin embargo, ha creado un nuevo objeto dentro del método del operador y lo ha devuelto como la salida del operador. Ahora se actualizará a para apuntar al objeto recién creado.
Entonces, a ahora apunta a un nuevo objeto, mientras que b sigue apuntando al original. Es por eso que la salida de WriteLine aparece intercambiada.
Como señaló @MarkusQ, el operador ++ está destinado a realizar modificaciones in situ. Al generar un nuevo objeto, estás rompiendo esa suposición. La sobrecarga del operador en objetos es un tema difícil, y este es un excelente ejemplo de por qué es mejor evitarlo en la mayoría de los casos.
1 - Solo por razones de precisión, la asignación no ocurre realmente antes del incremento cuando se trata de operadores en objetos, pero el resultado final es el mismo en este caso. En realidad, la referencia del objeto original se copia, la operación se lleva a cabo en el original, y luego la referencia copiada se asigna a la variable de la izquierda. Es más fácil de explicar si finges que la asignación ocurre primero.
Lo que realmente está sucediendo es que esto:
Account b = a++;
resulta en esto, debido a cómo funciona el operador ++ en los objetos:
Account copy = a;
Account x = new Account("operator ++", a.Balance);
a.Balance += 1; // original object''s Balance is incremented
a = x; // a now points to the new object, copy still points to the original
Account b = copy; // b and copy now point at the same, original, object
Tengo problemas al intentar sobrecargar el operador de incremento posterior en C #. Usando enteros obtenemos los siguientes resultados.
int n;
n = 10;
Console.WriteLine(n); // 10
Console.WriteLine(n++); // 10
Console.WriteLine(n); // 11
n = 10;
Console.WriteLine(n); // 10
Console.WriteLine(++n); // 11
Console.WriteLine(n); // 11
Pero, cuando lo intento usando clases, parece que los objetos se intercambian.
class Account
{
public int Balance { get; set; }
public string Name { get; set; }
public Account(string name, int balance)
{
Balance = balance;
Name = name;
}
public override string ToString()
{
return Name + " " + Balance.ToString();
}
public static Account operator ++(Account a)
{
Account b = new Account("operator ++", a.Balance);
a.Balance += 1;
return b;
}
public static void Main()
{
Account a = new Account("original", 10);
Console.WriteLine(a); // "original 10"
Account b = a++;
Console.WriteLine(b); // "original 11", expected "operator ++ 10"
Console.WriteLine(a); // "operator ++ 10", expected "original 11"
}
}
Al depurar la aplicación, el método del operador sobrecargado, devuelve el nuevo objeto con el valor antiguo (10) y el objeto que se ha pasado por referencia, tiene el nuevo valor (11), pero finalmente se intercambian los objetos. ¿Por qué está pasando esto?
Mi primer pensamiento fue señalar que la semántica normal de ++ es una modificación in situ . Si quieres imitar eso, escribirías:
public static Account operator ++(Account a)
{
a.Balance += 1;
return a;
}
y no crear un nuevo objeto.
Pero luego me di cuenta de que estabas intentando imitar el incremento de la publicación.
Así que mi segundo pensamiento es "no hagas eso": la semántica no se correlaciona bien con los objetos, ya que el valor que se está "utilizando" es realmente una ubicación de almacenamiento mutable. Pero a nadie le gusta que un extraño lo diga "no hagas eso", así que dejaré que Microsoft te diga que no lo hagas . Y temo que su palabra sea definitiva en tales asuntos.
PD En cuanto a por qué está haciendo lo que hace, realmente está anulando al operador de preincremento y luego lo está utilizando como si fuera el operador de postincremento.
Siempre debe devolver el valor cambiado. C # usa esto como el nuevo valor, y devuelve el valor antiguo o nuevo según sea apropiado para el operador.