sobreescritura - ¿Por qué no se puede sobrecargar ''='' en C#?
sobrecarga y escritura c# (12)
Tipo de Asignación Anulada
Hay dos tipos para anular la asignación:
- Cuando siente que el usuario puede perder algo, y quiere forzar al usuario a usar ''casting'' como float to integer, cuando pierde el valor flotante
int a = (int)5.4f;
- Cuando desea que el usuario haga eso sin siquiera darse cuenta de que está cambiando el tipo de objeto
float f = 5;
Cómo anular la asignación
Para 1, uso de explicit
palabra clave explicit
:
public static explicit override ToType(FromType from){
ToType to = new ToType();
to.FillFrom(from);
return to;
}
Para 2, uso de palabra clave implicit
:
public static implicit override ToType(FromType from){
ToType to = new ToType();
to.FillFrom(from);
return to;
}
Me preguntaba, ¿por qué no puedo sobrecargar ''='' en C #? ¿Puedo obtener una mejor explicación?
En realidad, el operator =
sobrecarga operator =
tendría sentido si pudiera definir clases con semántica de valor y asignar objetos de estas clases en la pila . Pero, en C #, no puedes.
Está permitido en C ++ y, si no se tiene cuidado, puede resultar en mucha confusión y en la búsqueda de errores.
Este artículo explica esto con gran detalle.
Este código está funcionando para mí:
public class Class1
{
...
public static implicit operator Class1(Class2 value)
{
Class1 result = new Class1();
result.property = value.prop;
return result;
}
}
Los lenguajes administrados por memoria usualmente trabajan con referencias en lugar de objetos. Cuando define una clase y sus miembros, está definiendo el comportamiento del objeto, pero cuando crea una variable, está trabajando con referencias a esos objetos.
Ahora, el operador = se aplica a las referencias, no a los objetos. Cuando asigna una referencia a otra, en realidad está haciendo que el punto de referencia de recepción sea el mismo objeto que la otra referencia.
Type var1 = new Type();
Type var2 = new Type();
var2 = var1;
En el código anterior, se crean dos objetos en el montón, uno referido por var1 y el otro por var2. Ahora la última declaración hace que el punto de referencia var2 sea el mismo objeto al que se refiere var1. Después de esa línea, el recolector de basura puede liberar el segundo objeto y solo hay un objeto en la memoria. En todo el proceso, ninguna operación se aplica a los objetos en sí.
Volviendo a por qué = no se puede sobrecargar, la implementación del sistema es lo único sensato que puede hacer con las referencias. Puede sobrecargar las operaciones que se aplican a los objetos, pero no a las referencias.
No creo que haya una sola razón realmente particular para señalar. En general, creo que la idea es la siguiente:
Si su objeto es un objeto grande y complicado, hacer algo que no sea una asignación con el operador
=
probablemente sea engañoso.Si su objeto es un objeto pequeño, también puede hacerlo inmutable y devolver nuevas copias al realizar operaciones en él, de modo que el operador de asignación trabaje de la manera que espera fuera de la caja (como lo hace
System.String
).
Porque dispararse en el pie está mal visto.
En una nota más seria, uno solo puede esperar que se refiera a la comparación en lugar de la asignación. El marco proporciona una disposición elaborada para interferir con la evaluación de igualdad / equivalencia, busque "comparar" en la ayuda o en línea con msdn.
Puede sobrecargar la asignación en C #. Simplemente no en un objeto entero, solo en miembros de él. Usted declara una propiedad con un setter:
class Complex
{
public double Real
{
get { ... }
set { /* do something with value */ }
}
// more members
}
Ahora, cuando asignas a Real
, se ejecuta tu propio código.
La razón por la que la asignación a un objeto no es reemplazable es porque ya está definido por el lenguaje como algo de vital importancia.
Sería útil definir una semántica especial para las operaciones de asignación, pero solo si dicha semántica pudiera aplicarse a todas las situaciones en las que una ubicación de almacenamiento de un tipo dado se copió a otra. Aunque el estándar C ++ implementa tales reglas de asignación, tiene el lujo de requerir que todos los tipos se definan en el momento de la compilación. Las cosas se complican mucho más cuando se agregan la reflexión y los genéricos a la lista.
Actualmente, las reglas en .net especifican que una ubicación de almacenamiento se puede establecer en el valor predeterminado para su tipo, independientemente de cuál sea ese tipo, al poner a cero todos los bytes. Además, especifican que cualquier ubicación de almacenamiento se puede copiar en otra del mismo tipo copiando todos los bytes. Estas reglas se aplican a todos los tipos, incluidos los genéricos. Dadas dos variables de tipo KeyValuePair<t1,t2>
, el sistema puede copiar una a otra sin tener que saber nada, excepto el tamaño y los requisitos de alineación de ese tipo. Si fuera posible para t1
, t2
, o el tipo de cualquier campo dentro de cualquiera de esos tipos , implementar un constructor de copia, el código que copia una instancia de estructura a otra tendría que ser mucho más complicado.
Eso no quiere decir que esa capacidad ofrezca algunos beneficios significativos, es posible que si se diseñara un nuevo marco, los beneficios de los operadores de asignación de valor personalizado y los constructores predeterminados excedieran los costos. Los costos de implementación, sin embargo, serían sustanciales en un nuevo marco, y probablemente serían insuperables para uno existente.
Si sobrecargó ''='' nunca podría cambiar una referencia de objeto después de que se haya creado. ... piénselo: cualquier llamada al objetoObjectWithOverloadedOperator = algo dentro del operador sobrecargado resultaría en otra llamada al operador sobrecargado ... entonces, ¿qué estaría haciendo realmente el operador sobrecargado? ¿Tal vez establecer otras propiedades o establecer el valor en un nuevo objeto (inmutabilidad)? Generalmente no es lo que ''='' implica ...
Sin embargo, puede anular los operadores de conversión implícitos y explícitos: http://www.blackwasp.co.uk/CSharpConversionOverload.aspx
Una posible explicación es que no puede hacer actualizaciones de referencia adecuadas si sobrecarga al operador de asignación. Literalmente, arruinaría la semántica porque cuando las personas esperaban que las referencias se actualizaran, su operador también puede estar haciendo algo completamente distinto. No muy amigable con el programador.
Puede usar operadores de conversión implícitos y explícitos para / de la mitigación para mitigar algunas de las fallas aparentes de no poder sobrecargar la asignación.
Porque realmente no tiene sentido hacerlo.
En C # = asigna una referencia de objeto a una variable. Así que opera sobre variables y referencias de objetos, no objetos en sí mismos. No tiene sentido sobrecargarlo según el tipo de objeto.
En C ++, el operador = tiene sentido para las clases cuyas instancias se pueden crear, por ejemplo, en la pila porque los objetos en sí mismos se almacenan en variables, no en referencias a ellas. Por lo tanto, tiene sentido definir cómo realizar dicha asignación. Pero incluso en C ++, si tiene un conjunto de clases polimórficas que normalmente se usan a través de punteros o referencias, usualmente prohíbe explícitamente copiarlas de esta manera declarando operator = y copiando constructor como privado (o heredando de boost :: noncopyable), debido a exactamente las mismas razones por las que no redefine = en C #. Simplemente, si tiene una referencia o un indicador de la clase A, realmente no sabe si apunta a una instancia de la clase A o la clase B, que es una subclase de A. Entonces, ¿realmente sabe cómo actuar = en esta situación?