c# - not - ¿Cómo se puede interpretar EXACTAMENTE los operadores+= y-=?
null c# operator (4)
Como dice la otra respuesta, el operador +
no está definido para la List<>
. Puede comprobarlo intentando sobrecargarlo, el compilador lanzará este error. One of the parameters of a binary operator must be the containing type
.
Pero como experimento, puede definir su propia clase heredando List<string>
y definir el operador +
. Algo como esto:
class StringList : List<string>
{
public static StringList operator +(StringList lhs, StringList rhs)
{
lhs.AddRange(rhs.ToArray<string>());
return lhs;
}
}
Entonces puedes hacer esto sin problemas:
StringList listString = new StringList() { "a", "b", "c" };
StringList listString2 = new StringList() { "d", "e", "f" };
listString += listString2;
Editar
Según el comentario de @EugeneRyabtsev, mi implementación del operador +
conduciría a un comportamiento inesperado. Así que debería ser algo más como esto:
public static StringList operator +(StringList lhs, StringList rhs)
{
StringList newList=new StringList();
newList.AddRange(lhs.ToArray<string>());
newList.AddRange(rhs.ToArray<string>());
return newList;
}
¿Qué hacen exactamente los operadores +=
y -=
(debajo del capó)?
¿O están implícitas en que están definidas por tipo?
Los he usado ampliamente, es una característica muy simple de la sintaxis, pero nunca he pensado en la profundidad de cómo funciona.
Lo que trajo sobre la pregunta
Puedo concatenar un valor de cadena así:
var myString = "hello ";
myString += "world";
Todo muy bien. Pero ¿por qué no funciona esto con colecciones?
var myCol = new List<string>();
myCol += "hi";
Puede decir ''bueno, está intentando agregar un tipo diferente, no puede agregar una cadena a un tipo que no es una cadena''. Pero lo siguiente tampoco funciona:
var myCol = new List<string>();
myCol += new List<string>() { "hi" };
Ok, tal vez no funcione con colecciones, pero ¿es el siguiente no un (tipo de) colección de controladores de eventos?
myButton.Click += myButton_Click;
Obviamente me falta una comprensión profunda de cómo funcionan estos operadores.
Por favor, tenga en cuenta: no estoy intentando construir la colección myCol
de esta manera, en un proyecto real. Simplemente siento curiosidad por el funcionamiento de este operador, es hipotético.
El operador +=
se define implícitamente de esta manera: a += b
convierte en a = a + b;
, lo mismo con el operador -=
.
(advertencia: como señaló Jeppe , si a
es una expresión, solo se evalúa una vez si usas a+=b
, pero dos veces con a=a+b
)
No puede sobrecargar el operador +=
y -=
separado. Cualquier tipo que admita el operador +
también admite +=
. Puede agregar soporte para +=
y -=
a sus propios tipos sobrecargando +
y -
.
Sin embargo, hay una excepción codificada en c #, que ha descubierto:
Los eventos tienen un operador +=
y -=
, que agrega y elimina un controlador de eventos a la lista de controladores de eventos suscritos. A pesar de esto, no son compatibles con los operadores +
y -
.
Esto no es algo que pueda hacer por sus propias clases con la sobrecarga del operador regular.
La implementación correcta es en realidad un poco más compleja de lo que uno podría pensar. En primer lugar, no es suficiente decir que a += b
es exactamente lo mismo que a = a+b
. Tiene la misma semántica en los casos más simples, pero no es una simple sustitución de texto.
Primero, si la expresión de la izquierda es más compleja que una simple variable, solo se evalúa una vez. Así que M().a += b
no es lo mismo que M().a = M().a + b
, ya que asignaría el valor a un objeto completamente diferente del que se tomó, o causaría que Los efectos secundarios del método se producen dos veces.
Si M()
devuelve un tipo de referencia, el operador de asignación compuesto se puede considerar como var obj = M(); obj.a = obj.a+b;
var obj = M(); obj.a = obj.a+b;
(pero sigue siendo una expresión). Sin embargo, si obj
era de un tipo de valor, esta simplificación tampoco funcionaría, en caso de que el método devolviera una referencia (nueva en C # 7) o si en realidad fuera un elemento de matriz, o algo devuelto por un indexador, etc. el operador se asegura de que no haga más copias de las necesarias para modificar el objeto, y se aplicará en un lugar correcto, sin efectos secundarios adicionales.
Sin embargo, la asignación de eventos es una bestia completamente diferente. Fuera del alcance de la clase , +=
da como resultado que se llama al elemento de acceso a agregar , y -=
traduce a que se llama al elemento de acceso de eliminación del evento. Si estos accesores no son implementados por el usuario, la asignación de eventos podría resultar en la llamada a Delegate.Combine y Delegate.Remove en el objeto de delegado interno dentro del alcance de la clase. Por eso también no puede simplemente obtener el objeto de evento fuera de la clase, porque no es público. +=
/ -=
tampoco es una expresión en este caso.
Recomiendo leer la asignación de compuestos por Eric Lippert. Describe esto con mucho más detalle.
La respuesta corta es que los operadores en C # tienen que estar sobrecargados para un tipo dado. Esto también es válido para +=
. string
contiene una sobrecarga de este operador, pero la List<>
no lo ha hecho. Por lo tanto, no es posible utilizar el operador +=
para listas. Para los delegados, el operador +=
también está sobrecargado, por lo que puede usar +=
en los controladores de eventos.
La respuesta un poco más larga es que usted mismo es libre de sobrecargar al operador. Sin embargo, debe sobrecargarlo para sus propios tipos, por lo que no es posible crear una sobrecarga para la List<T>
, mientras que de hecho puede hacerlo para su propia clase que, por ejemplo, hereda de la List<T>
.
Técnicamente, realmente no sobrecargas el operador +=
, sino el operador +
. El operador +=
luego se deduce al combinar el operador +
con una asignación. Para que esto funcione, el operador +
debe estar sobrecargado de tal manera que el tipo de resultado coincida con el tipo del primer argumento, de lo contrario, el compilador C # arrojará un mensaje de error cuando intente usar +=
.