then question operator mark c# c#-6.0 null-conditional-operator

question - null c# operator



¿Es C#6?(Elvis op) hilo seguro? ¿Si es así, cómo? (2)

De MSDN (énfasis mío):

Otro uso para el acceso de miembros con condición nula es invocar delegados de una manera segura para subprocesos con mucho menos código. La forma antigua requiere código como el siguiente:

var handler = this.PropertyChanged; if (handler != null) handler(…)

La nueva forma es mucho más simple:

PropertyChanged?.Invoke(e)

La nueva forma es segura para subprocesos porque el compilador genera código para evaluar PropertyChanged solo una vez, manteniendo el resultado en una variable temporal .

Por lo tanto, no hay bloqueo involucrado aquí: la seguridad de subprocesos se impone al crear una variable temporal local, lo que evita que un subproceso diferente modifique esa variable entre la comprobación nula y alguna otra operación.

Disculpas por adelantado: esta pregunta proviene de un desarrollador de C ++ no reformado que intenta aprender C # avanzado. Considera lo siguiente:

if (myUserDefinedObject != null) { myUserDefinedObject.ToString(); }

Esto obviamente no es seguro para subprocesos. Por otro lado, he visto dos tutoriales que dicen?. (el operador condicional nulo o ''operador de Elvis'') por ejemplo,

myUserDefinedObject?.ToString();

IS hilo seguro. A menos que el compilador envuelva un bloqueo [¿mutex?] Alrededor de él debajo de las cubiertas (escalofrío), no entiendo cómo puede ser cierto. Si este lenguaje es seguro para subprocesos, ¿puede alguien indicarme una descripción técnica de cómo se logra eso? Si no es seguro para subprocesos, ¿alguien tiene una referencia que realmente dice que no lo es?


Quiero aclarar la respuesta (correcta) de BJ Myers.

En C #, un evento se puede considerar como un campo de tipo delegado, al igual que una propiedad se puede considerar como un campo del tipo de propiedad, y el valor de ese "campo" puede ser nulo. Si se encuentra en la desafortunada situación de tener un controlador de eventos modificado en un subproceso mientras otro subproceso intenta invocarlo, puede ingresar a la situación en la que:

if (this.SomeEvent != null) this.SomeEvent( ... );

no es seguro para hilos. El valor podría mutarse de modo que no sea nulo antes de la comprobación, nulo después de la comprobación y el programa se bloquee.

La forma habitual de hacer este "seguro para subprocesos", y uso el término de manera aconsejable, es copiar el valor en un local y luego probar el local para determinar si es nulo. Esto tiene la ventaja de no estrellarse con una falta de referencia nula. Sin embargo, el desarrollador inteligente notará que todavía hay una carrera! La secuencia puede ser

  • Controlador de eventos no nulos en caché en el subproceso A
  • Controlador de eventos establecido en nulo en el subproceso B
  • El estado que necesita el controlador de eventos se destruye en el subproceso B
  • El controlador de eventos se ejecuta en el hilo A y muere horriblemente

Entonces, en ese sentido, este patrón no es "seguro para subprocesos". Si se encuentra en esta posición desafortunada , es responsable de garantizar que se implemente la lógica de subprocesos adecuada para que esto no pueda suceder . Puedes hacer eso como quieras. Si desea los beneficios (cuestionables) de poder llamar a un controlador de eventos en un hilo mientras se muta el evento en otro hilo, entonces tiene que pagar para hacerlo seguro o para lidiar con errores de condición de carrera.

Personalmente evitaría esta situación como la plaga, pero no soy lo suficientemente inteligente como para escribir el código de multiproceso correcto.

Ahora, en cuanto a la pregunta real:

some_expression ?. ToString();

es lo mismo que

temp = some_expression temp == null ? null : temp.ToString()

¿Es este último código "seguro para hilos" en tu opinión?