Esta es una pregunta planteada por uno de los miembros de nuestro equipo durante el proceso de programación. Debido a que este error de compilación es fácil de evitar, nunca pensé detenidamente en este problema hasta que miré su código y me di cuenta de que este problema no es tan simple.
Eche un vistazo a este código primero:
código
programa de clase
{
vacío estático principal (cadena [] argumentos)
{
byte[] buf = nuevo byte[1024];
T t = nueva T();
cadena cadena = "1234";
entero norte = 1234;
int?nn = 1234;
FechaHora dt = FechaHora.Ahora;
objeto o = 1234;
Console.WriteLine("finalizar");
}
}
clase T {}
¿Cuántas variables crees que no se utilizan en este código?
Si lo miras desde la perspectiva de un programador, la respuesta debería ser que todas las variables no se utilizan. Pero el resultado dado por el compilador es un poco contradictorio:
A la variable "str" se le ha asignado un valor, pero su valor nunca se ha utilizado. A la variable "n" se le ha asignado un valor, pero a su valor nunca se le ha asignado un valor. El valor nunca se ha utilizado.
Lo extraño es que aunque todas las variables se declaran de la misma manera, el compilador sólo piensa que algunas de ellas no se utilizan. ¿Qué está sucediendo?
Analicémoslos uno por uno. Primero mire la matriz. Si se usa el valor predeterminado, la información proporcionada por el compilador es diferente:
byte[] buf1 = null // Hay una advertencia
byte[] buf2 = nuevo byte[1024] // sin advertencia
Este resultado parece indicar que si la asignación de parámetros es nula, el compilador en realidad no realizará la asignación y la variable se tratará como si no se hubiera utilizado. Los resultados de la inspección de IL también pueden probar esta afirmación: para la primera línea, el compilador no generó ninguna declaración correspondiente, para la segunda línea, se utilizó la instrucción newattr para crear la matriz;
Para clases personalizadas:
T t1 = nulo // Hay una advertencia
T t2 = nuevo T(); // sin advertencia
Este resultado debería ser comprensible (aunque es comprensible, no creo que sea bueno, por las razones que se muestran a continuación). Aunque no llamamos a ningún método de la clase, el constructor de la clase aún puede realizar algunas operaciones, por lo que siempre que se cree una clase, el compilador la tratará como si ya se hubiera utilizado.
Para los tipos de valores básicos, su comportamiento es diferente al de los tipos de referencia. El compilador no trata la asignación inicial como un uso de variables:
int n1 = 0; // Hay una advertencia
int n2 = 1234 // Hay una advertencia
int? n3 = nulo; // Hay una advertencia
int? n4 = 0; // Hay una advertencia
int? n5 = 1234 // Hay una advertencia
La cadena debe considerarse como un tipo de referencia en términos de implementación, pero su rendimiento es más similar al de un tipo de valor y la información de advertencia es la misma que la de un tipo de valor.
Para tipos de valores ligeramente más complejos, los resultados son un poco más sutiles:
DateTime dt1; // Hay una advertencia
DateTime dt2 = new DateTime(); // Hay una advertencia
DateTime dt3 = new DateTime(2009,1,1); // sin advertencia;
DateTime dt4 = DateTime.Now // sin advertencia
Hay una cosa a tener en cuenta sobre este resultado. Aunque el constructor predeterminado de DateTime y el constructor parametrizado son constructores desde la perspectiva del usuario, son diferentes desde la perspectiva del compilador. También se puede ver al descompilar con IL que si se llama al constructor predeterminado, el compilador llama a la instrucción initobj, mientras que la instrucción call ctor se usa para el constructor parametrizado. Además, aunque el formato del código de asignación es exactamente el mismo desde la perspectiva del programador, el compilador adoptará diferentes estrategias de construcción según el valor asignado, lo que también es contrario a la intuición.
La conclusión final es lamentable, es decir, las advertencias de compilación de C# no son suficientes para brindar a los programadores suficiente protección, especialmente para las matrices:
byte[] buf = nuevo byte[1024];
Si solo construye una matriz de este tipo sin usarla, el compilador no le dará al programador ningún mensaje de advertencia.
Otro tema que vale la pena considerar es declarar una clase sin utilizar ningún método, como simplemente
Tt = nuevo T()
¿Es este comportamiento razonable? ¿Debería el compilador emitir una advertencia por esto?
Mi opinión personal es que desde una perspectiva de uso, esto no es razonable y debe evitarse tanto como sea posible. El compilador debería emitir una advertencia si descubre este uso. Si es necesario, puede evitar mensajes de advertencia declarándolos específicamente mediante directivas de compilación o métodos de atributos. Sin embargo, el comportamiento del compilador de C# es no emitir advertencias, con lo cual no estoy de acuerdo. Por supuesto, también espero que cada uno presente sus propias ideas.