2009-04-15 7 views

Respuesta

14

Los campos se inicializan automáticamente al cero lógico para el tipo; esto es implícito Las variables deben obedecer a "asignación definida", por lo que debe asignarse antes de que puedan leerse.

ECMA 334v4

§17.4.4 inicialización Campo

El valor inicial de un campo, si se trate de un campo estático o un campo de instancia , es el valor por defecto (§12.2) de el tipo del campo. No es posible observar el valor de un campo antes de que esta inicialización predeterminada tiene ocurrido, y un campo nunca es así "no inicializado".

y

§12. Variables

... Se debe asignar definitivamente una variable (§12.3) antes de obtener su valor . ...

+0

eso es sólo la repetición de la pregunta. ¿Pero por qué? –

+0

@YairHalberstadt que depende de si por "¿por qué?" uno significa la regla o la razón detrás de la regla. Respondí el primero, lo que podría decirse que responde la pregunta; para el segundo: porque para cuando consideramos el encadenamiento de constructores, los métodos virtuales que se invocan durante la construcción y el hecho de que en el nivel IL se pueden llamar constructores base en cualquier punto de la cadena de llamadas, es casi imposible decir nada sensible a la inicialización de campo; igualmente, los campos pueden superponerse, por lo que es aún más importante poner a cero el espacio, por lo que no se requiere init; contraste ... –

+0

@YairHalberstadt variables locales, que tienen una verificación de asignación muy sencilla, donde no inicializado usualmente significa un error, y donde puede omitir el ajuste a cero (aunque el tiempo de ejecución actual nunca lo hace, IIRC). –

4

En realidad no debería. Su error debe estar en la segunda línea, no en la primera, y debe ser porque USTED lo utilizó antes de inicializarlo.

El compilador te está ayudando aquí.

Así que no los inicialices como un hábito, en cambio deja que el compilador te ayude.

Lo bueno de esto es que comprobará el camino por usted. Si tiene una declaración de cambio con 3 casos en los que cada uno establece el valor pero se olvida de configurarlo en su "valor predeterminado", pero luego lo usa, le avisará que perdió un camino.

Si inicializa las variables a = 0, le quita ese beneficio.

+0

También utilicé test1 antes de inicializarlo, pero estaba bien –

+0

Sí, la misma comprobación no es útil con variables de clase: no hay forma de rastrearlas a menos que las haga definitivas, entonces debería asegurarse de que sean completado en el constructor (una buena idea siempre que sea posible) –

+0

Aunque su ruta de verificación no es demasiado elegante. Por ejemplo, digamos que tienes algo así: 'bool a, b = true; si (b) a = verdadero; bool c = a; '. El tercer enunciado ** generará ** el error, aunque nosotros, los humanos, veamos claramente que 'a' ** se ** inicializará para entonces. El compilador no se ve dentro de las condiciones, incluso cuando son tan simples y verdaderas. (Y también se aplica a casos más complicados). – Sushi271

2

Como Marc indica, eso es lo que dice la especificación. La razón por la cual esto es bueno es que hay algunas razones válidas para dejar a un miembro sin inicializar en lugar de una variable local, cuya duración está limitada por el método en el que se encuentra. En su mayoría, solo desearía esto por motivos de rendimiento, si la variable es costosa de inicializar y solo debe inicializarse en escenarios de uso específicos. ¡Por mi parte, evitaría a los miembros no inicializados hasta que mi espalda estuviera realmente contra la pared!

Para las variables locales, también es mucho más fácil detectar si todas las rutas de código conducen a la inicialización, mientras que no hay buenas heurísticas para determinar si todas las rutas de código en todo el programa garantizan la inicialización antes del uso. Una respuesta completamente correcta es impossible in both cases, como todos los estudiantes de CS deberían saber.

12

Extendiendo La respuesta de la marca, la inicialización de la variable local también está relacionada con el proceso de verificación .
La CLI requiere que en cualquier código verificable (es decir, módulos que no pidieron explícitamente omitir el proceso de verificación utilizando la propiedad SkipVerfication del atributo SecurityPermission), todas las variables locales se deben inicializar antes de su uso. De lo contrario, se generará un VerficationException.

Más interesante aún, es que el compilador agrega automáticamente el indicador .locals init en cada método que utiliza variables locales. Este indicador hace que el compilador JIT genere código que inicializa todas las variables locales a sus valores predeterminados. Es decir, aunque ya los haya inicializado en su propio código, el JIT cumplirá con el indicador .locals init y generará el código de inicialización adecuado. Esta "inicialización duplicada" no afecta el rendimiento ya que en las configuraciones que permiten optimizaciones, el compilador JIT detectará la duplicación y la tratará efectivamente como "código muerto" (la rutina de inicialización generada automáticamente no aparecerá en las instrucciones del ensamblador generado).

Según Microsoft (también, respaldado por Eric Lippert en respuesta a una pregunta en su blog), en la mayoría de las ocasiones, cuando los programadores no inicializan su variable local, no lo hacen porque transmiten en el entorno subyacente para inicializar su variable a sus valores predeterminados, pero solo porque se "olvidó", causando errores lógicos a veces ilusorios.
Para reducir la probabilidad de que aparezcan errores de esta naturaleza en el código C#, el compilador aún insiste en que inicializará sus variables locales. Aunque va a agregar el indicador .locals init al código IL generado.

Una explicación más amplia sobre este tema se puede encontrar aquí: Behind The .locals init Flag

Cuestiones relacionadas