sharp from compiler compile comando c# compiler-construction

c# - from - csc c sharp compiler



¿Por qué NO recibo advertencias sobre campos de lectura no inicializados? (4)

El compilador de C # tiene la amabilidad de brindarle un "campo que nunca se asigna a" advertencia si olvida inicializar un miembro de solo lectura que sea privado o interno, o si la clase en la que se declara es interna. Pero si la clase es pública, y el miembro de solo lectura es público, está protegido o está protegido internamente, ¡entonces no hay ninguna advertencia para usted!

¿Alguien sabe por qué?

Código de muestra que demuestra las condiciones bajo las cuales se emite la advertencia y las condiciones bajo las cuales no se emite la advertencia:

namespace Test1 { class Test1 { #if TRY_IT public readonly int m; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0 protected readonly int n; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0 internal readonly int o; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0 private readonly int p; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0 protected internal readonly int q; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0 Test1() { if( p != 0 ) //To avoid warning ''The field is never used'' return; } #endif } public class Test2 { #if TRY_IT private readonly int m; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0 internal readonly int n; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0 Test2() { if( m != 0 ) //To avoid warning ''The field is never used'' return; } #endif public readonly int o; //Blooper: no warning about field never assigned to. protected readonly int p; //Blooper: no warning about field never assigned to. protected internal readonly int q; //Blooper: no warning about field never assigned to. } public sealed class Test3 { public readonly int m; //Blooper: no warning about field never assigned to. } }

EDITAR: Por un momento, podría pensar que el compilador se abstiene de emitir la advertencia en el caso de miembros públicos y protegidos porque es razonable esperar que las clases derivadas puedan inicializar el campo. Esta teoría no contiene agua por varias razones:

  • Una clase interna puede ser subclasificada, pero el compilador no se abstiene de emitir la advertencia en ese caso.

  • El compilador no emite la advertencia incluso en el caso de una clase sellada, como lo demuestra Test3 en el código de ejemplo.

  • La advertencia tiene sentido por el bien de la integridad de la clase base, independientemente de lo que una clase derivada pueda o no pueda hacer.

  • El idioma prohíbe expresamente que una clase inicialice un miembro de solo lectura de una clase base. (Gracias, Jim Mischel.)

EDIT2: si mi memoria me sirve bien, Java da todas las advertencias adecuadas en todos los casos, independientemente de si el miembro final sin inicializar es público, protegido o privado, y sin importar si la clase que lo contiene es pública o visible solo dentro de su paquete.


Creo que es debido a la advertencia relacionada con el alcance y el uso. Se puede acceder al miembro público y protegido fuera del alcance del conjunto y por el consumidor de la clase, y el desarrollador puede querer que el valor de la variable sea su valor predeterminado.

Por otro lado, los miembros privados e internos se utilizan internamente, y usted lo hace solo porque no quiere que lo cambie por error, por lo que es muy probable que deba inicializarse en algún lugar.


Esta es la documentación de MSDN: Advertencia del compilador (nivel 4) CS0649 :

El campo ''campo'' nunca se asigna a, y siempre tendrá su valor predeterminado ''valor''

El compilador detectó una declaración de campo interno o privado sin inicializar que nunca tiene asignado un valor.

Por lo tanto, para los campos no internos y no privados, no debe esperar tener una advertencia.

Pero creo que la razón principal es que el compilador de C # cree que debe inicializar todas las cosas que son accesibles solo desde su ensamblaje. Supongo que el compilador de C # lo dejó a los demás para inicializar campos no privados y no internos en su ensamblaje.

Pero lo probé con protected internal y no sé por qué el compilador de C # no advierte al respecto.


La respuesta corta: esto es un descuido en el compilador.

La respuesta más larga: la heurística que determina qué advertencias emitir a los miembros y locales que se declaran y nunca se usan, o se escriben y nunca se leen, o se leen y nunca se escriben, no tienen en cuenta la capacidad de solo lectura del campo. Como nota correctamente, podría y, por lo tanto, emitir advertencias en más casos. Podríamos decir que un campo público de solo lectura que no se inicializa en ningún ctor "siempre tendrá su valor predeterminado", por ejemplo.

Se lo mencionaré a Neal en el nuevo año y veremos si podemos mejorar esas heurísticas en Roslyn.

Incidentalmente, hay una serie de situaciones en las que se puede emitir una advertencia de este tipo (independientemente de que sea de solo lectura) pero no lo hacemos. Hoy no estoy en mi oficina, así que no tengo mi lista de todas esas situaciones a mano, pero basta con decir que hay muchas de ellas. Era algo como "el campo está declarado como público y está en una clase anidada pública de una clase interna". En esa situación, el campo es efectivamente interno y podemos hacer la advertencia, pero a veces no lo hacemos.

Hace un año, hace muchos años, cambié la heurística para que cada campo que se sabía que no se usaba de forma estática produjera una advertencia, y cuando ese cambio se incorporara a la versión interna del compilador de C # que utilizamos para compilar las bibliotecas de clases que están escritas en C #, todo el infierno se desató. Esos tipos siempre compilan con las "advertencias como errores" activadas, y de repente comenzaron a recibir advertencias en todo tipo de campos que se iniciaron o utilizaron deliberadamente a través de la reflexión y otras técnicas dinámicas. Rompí la construcción de una manera importante. Ahora, uno podría argumentar que estos tipos deberían corregir su código para que suprima la advertencia (y yo lo argumenté), pero al final resultó ser más fácil hacer retroceder la heurística de advertencia a su nivel anterior. Debería haber hecho el cambio más gradualmente.


Si es público (o, mejor dicho, no privado), puede ser usado por otra clase fuera de su proyecto. Esto es importante para construir bibliotecas que deberían ser utilizadas por otros. Si recibiera una advertencia por cada propiedad, campo o método público no utilizado, no vería los problemas reales.