Vengo de C ++ y encuentro un comportamiento muy diferente entre los punteros en C ++ y C #.
Sorprendentemente encuentro que este código compila ... E incluso ... Funciona perfectamente.
class C
{
private readonly int x = 0;
unsafe public void Edit()
{
fixed (int* p = &x)
{
*p = x + 1;
}
Console.WriteLine($"Value: {x}");
}
}
Esto me deja muy perplejo, incluso en C ++ tenemos un mecanismo para proteger const
objetos ( const
en C ++ casi lo mismo que readonly
en C #, no const
en C #), porque no tenemos suficientes razones para modificar arbitrariamente los valores const a través de punteros.
Al explorar más, encuentro que no hay equivalente a los punteros constantes de bajo nivel de C ++ en C #, que será algo así como:
readonly int* p
en C # si tuviera uno.
Entonces p solo puede leer el objeto señalado y no puede escribirle.
Y para los const
objetos, C # prohibió los intentos de recuperar su dirección.
En C ++, cualquier intento de modificar el const
es un error de compilación o un Comportamiento indefinido. En C #, no sé si existe alguna posibilidad de que podamos hacer uso de esto.
Entonces mi pregunta es:
- ¿Está este comportamiento realmente bien definido? Aunque sé que en C # no hay un concepto como UB en C ++
- Si es así, ¿cómo debo usarlo? ¿O nunca lo usas?
Nota: En la sección de comentarios: el rechazo const
en C ++ no está relacionado con esta pregunta, porque es válido solo cuando el objeto señalado en sí no lo está const
; de lo contrario, es UB. Además, básicamente estoy hablando de C # y el comportamiento del tiempo de compilación.
Puede pedirme que proporcione más detalles si no comprende completamente la pregunta. Descubrí que la mayoría de la gente no puede entender esto correctamente, tal vez es mi culpa no dejarlo claro.
fuente
Respuestas:
Me gustaría poder decir que solo obtienes este comportamiento inesperado debido a la
unsafe
palabra clave. Desafortunadamente, hay al menos dos formas más de cambiar ese campo de solo lectura, que ni siquiera requieren inseguridad. Puede encontrar más información sobre estos métodos en la publicación de blog de Joe Duffy 'Cuando es un campo de solo lectura no solo de lectura' .Al superponer un campo con una estructura no de solo lectura:
Y al alias accidentalmente
this
con un parámetro ref (este se hace desde afuera):Los tres métodos están perfectamente definidos en C # que debes evitar como la peste. Solo imagine el código de depuración con problemas complejos de alias derivados de fuera de su clase. Desafortunadamente, todavía no hay una solución satisfactoria para detener los problemas de alias en C #.
fuente