sintactico sharp semantico lexico hacer desde descargar crear compilador como cero analizador c# compiler-warnings visual-studio-mac

sharp - ¿Falsa advertencia del compilador de C#?



compilador c# descargar (2)

En el primer ejemplo, se asigna foo , pero nunca se lee. El 0 se asigna a foo , luego se devuelve 0 , independientemente de cuál sea el valor de foo (por ejemplo, si otro hilo lo mutó mientras tanto).

En el segundo ejemplo, se asigna foo , luego se lee de. Si otro hilo modificó foo mientras tanto, se devolverá el valor modificado, no 0 .

Puedes ver esto en acción comparando el IL compilado. Dado el siguiente código:

public class Foo { private int foo; public int Reset() { return (foo = 0); } public int Reset2() { foo = 0; return foo; } }

La siguiente IL está compilada para Reset y Reset2 .

.method public hidebysig instance int32 Reset () cil managed { .maxstack 3 .locals init ( [0] int32 ) IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: dup IL_0003: stloc.0 IL_0004: stfld int32 Foo::foo IL_0009: ldloc.0 IL_000a: ret } .method public hidebysig instance int32 Reset2 () cil managed { .maxstack 8 IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: stfld int32 Foo::foo IL_0007: ldarg.0 IL_0008: ldfld int32 Foo::foo IL_000d: ret }

En Reset , solo almacenamos en Foo::foo ( stfld ).

En Reset2 , puede ver que tanto almacenamos como stfld desde él ( stfld + ldfld ).

Ok, este es un caso de esquina muy extendido con el que tropezamos, pero me dio curiosidad.

Considere el siguiente código:

public class Foo { private int foo; public int Reset() => foo = 0; //remember, assignment expressions //return something! }

¿Se compilará este código?

No, no lo hará si ha fallado en todas las advertencias; obtendrá un member foo is assigned but never used advertencia.

Este código es, a todos los efectos, el mismo que:

public class Foo { private int foo; public int Reset() { foo = 0; return foo; } }

Que compila bien, ¿cuál es el problema aquí? Tenga en cuenta que la sintaxis => no es el problema, sino que devuelve la expresión de asignación que parece confundir al compilador.


Para responder esto en términos C # puros, el valor de una expresión de asignación es el valor asignado. Podemos demostrar esto así:

public class Foo { public int Bar { get { return 2; } set { /* do nothing */ } } } /* … */ Foo foo = new Foo(); Console.WriteLine(foo.Bar = 23);

Esto imprime 23 en la consola porque el valor de foo.Bar = 23 es 23 aunque el valor de foo.Bar siempre es 2 .

La mayoría de las veces, el único efecto de esto es un beneficio de rendimiento menor, porque la mayoría de las veces el valor de la propiedad o el campo será lo que se le asignó, pero solo podemos reutilizar el valor local que ya tenemos en lugar de Accediendo a esa propiedad de campo.

La advertencia aquí no solo es técnicamente correcta, sino que también es útil: dado que foo nunca se lee realmente, es solo una pérdida de memoria tenerlo y tiempo para asignárselo, y debe eliminarlo como cruft. (O, por supuesto, continúe desarrollándose para que aparezca un caso para el que no se ha codificado todavía).