válido specification software significado programa medicina language español detectó common abreviatura c# clr

c# - specification - common language runtime detectó un programa no válido



¿Las variables sin inicializar de C#son peligrosas? (6)

Estoy familiarizado con la especificación C #, sección 5.3 que dice que una variable debe asignarse antes de su uso.

En C y C ++ no administrado, esto tiene sentido ya que la pila no se borra y la ubicación de la memoria utilizada para un puntero podría estar en cualquier lugar (lo que lleva a un error difícil de rastrear).

Pero tengo la impresión de que no hay valores verdaderamente "no asignados" permitidos por el tiempo de ejecución. En particular, un tipo de referencia que no se inicializa siempre tendrá un valor nulo, nunca el valor restante de una invocación previa del método o valor aleatorio.

¿Es correcto o he asumido erróneamente que un cheque de nulo es suficiente todos estos años? ¿Puede tener realmente variables no identificadas en C #, o CLR se ocupa de esto y siempre hay ALGUNOS valores establecidos?


En particular, que un tipo de referencia que no se inicialice siempre tendrá un valor nulo

Creo que estás mezclando variables locales y variables miembro. La Sección 5.3 habla específicamente sobre variables locales. A diferencia de las variables miembro que sí reciben el valor predeterminado, el valor local nunca se establece por defecto en valor nulo o cualquier otra cosa: simplemente deben asignarse antes de que se lean por primera vez. La Sección 5.3 explica las reglas que el compilador usa para determinar si una variable local ha sido asignada o no.


Tengo la impresión de que no hay valores realmente "no asignados" permitidos por el tiempo de ejecución. En particular, un tipo de referencia que no se inicializa siempre tendrá un valor nulo, nunca el valor restante de una invocación previa del método o valor aleatorio. ¿Es esto correcto?

Observo que nadie ha respondido tu pregunta todavía.

La respuesta a la pregunta que realmente hizo es "sorta".

Como otros han notado, algunas variables (elementos de matriz, campos, etc.) se clasifican como "inicialmente asignadas" automáticamente a su valor predeterminado. (Que es nulo para los tipos de referencia, cero para los tipos numéricos, falso para los bools y la recursión natural para las estructuras definidas por el usuario).

Algunas variables no se clasifican como inicialmente asignadas; las variables locales, en particular, no están asignadas inicialmente. El compilador debe clasificarlos como "definitivamente asignados" en todos los puntos donde se usan sus valores .

En realidad, su pregunta es "¿una variable local que está clasificada como no asignada definitivamente en realidad se asignó inicialmente de la misma manera que un campo?" Y la respuesta a esa pregunta es , en la práctica, el tiempo de ejecución inicialmente asigna a todos los lugareños.

Esto tiene varias buenas propiedades. En primer lugar, puede observarlos en el depurador para que estén en su estado predeterminado antes de su primera asignación. En segundo lugar, no hay ninguna posibilidad de que el recolector de basura sea engañado para desreferenciar un puntero malo solo porque quedaba basura en la pila que ahora se está tratando como una referencia administrada. Y así.

Se permite que el tiempo de ejecución deje el estado inicial de los locales como cualquier basura que haya allí si puede hacerlo de manera segura. Pero como detalle de implementación, nunca elige hacerlo. Borra la memoria de una variable local de forma agresiva.

La razón entonces para la regla de que los lugareños deben asignarse definitivamente antes de que se usen no es para evitar que se observe el estado basura no inicializado del local. Eso ya es inobservable porque el CLR borra agresivamente a los lugareños a sus valores predeterminados, al igual que para los campos y los elementos de la matriz. La razón por la cual esto es ilegal en C # es porque el uso de un local no asignado tiene una alta probabilidad de ser un error. Simplemente lo hacemos ilegal, y luego el compilador evita que tenga ese error.


Depende de dónde se declara la variable. Las variables declaradas dentro de una clase se inicializan automáticamente utilizando el valor predeterminado.

object o; void Method() { if (o == null) { // this will execute } }

Las variables declaradas dentro de un método no se inicializan, pero cuando la variable se usa por primera vez, el compilador verifica para asegurarse de que se inicializó, por lo que el código no se compilará.

void Method() { object o; if (o == null) // compile error on this line { } }


Hasta donde yo sé, cada tipo tiene un valor predeterminado designado.

Según este documento, los campos de clases tienen asignado el valor predeterminado.

http://msdn.microsoft.com/en-us/library/aa645756(v=vs.71).aspx

Este documento dice que los siguientes siempre tienen valores predeterminados asignados automáticamente.

  • Variables estáticas
  • Variables de instancia de instancias de clase.
  • Variables de instancia de variables de estructura asignadas inicialmente.
  • Elementos de matriz
  • Parámetros de valor
  • Parámetros de referencia.
  • Variables declaradas en una cláusula catch o en una declaración foreach.

http://msdn.microsoft.com/en-us/library/aa691173(v=vs.71).aspx

Más información sobre los valores predeterminados reales aquí: http://msdn.microsoft.com/en-us/library/83fhsxwc.aspx


Hay 3 formas en que a una variable se le puede asignar un valor inicial:

  1. De forma predeterminada, esto sucede (por ejemplo) si declara una variable de clase sin asignar un valor inicial, por lo que el valor inicial obtiene el valor default(type) donde el type es el tipo que declara que es la variable.

  2. Con un inicializador, esto sucede cuando declaras una variable con un valor inicial, como en int i = 12;

  3. Cualquier punto antes de recuperar su valor: esto sucede (por ejemplo) si tiene una variable local sin valor inicial. El compilador asegura que no tiene rutas de acceso accesibles que lean el valor de la variable antes de que se asigne.

En ningún momento el compilador le permitirá leer el valor de una variable que no se ha inicializado, por lo que nunca tendrá que preocuparse por lo que sucedería si lo intentara.


Todos los tipos de datos primitivos tienen valores predeterminados, por lo que no debe preocuparse por ellos.

Todos los tipos de referencia se inicializan en valores nulos, de modo que si deja los tipos de referencia sin inicializar y luego llama a algún método o propiedad en ese tipo de ref nulo, obtendrá una excepción de tiempo de ejecución que deberá manejarse correctamente.

De nuevo, todos los tipos Nullable deben verificarse para valores nulos o predeterminados si no se inicializan de la siguiente manera:

int? num = null; if (num.HasValue == true) { System.Console.WriteLine("num = " + num.Value); } else { System.Console.WriteLine("num = Null"); } //y is set to zero int y = num.GetValueOrDefault(); // num.Value throws an InvalidOperationException if num.HasValue is false try { y = num.Value; } catch (System.InvalidOperationException e) { System.Console.WriteLine(e.Message); }

Pero no obtendrá ningún error de compilación si deja sin inicializar todas sus variables, ya que el compilador no se quejará, es solo el tiempo de ejecución del que debe preocuparse.