2010-03-25 21 views
16

tengo el siguiente fragmento de código:no inicializado variable en C#

class Foo 
{ 

    public Foo() 
    { 
     Bar bar; 
     if (null == bar) 
     { 

     } 
    } 
} 

class Bar { } 

gurús código ya verán que esto da un error. Es posible que Bar no se inicialice antes de la instrucción if.

Así que ahora me pregunto: ¿cuál es el vlaue de la barra, no debería ser nulo? ¿No están establecidos en nulo? (nullpointer?)

+0

En ese momento, Bar apunta a un lugar en la pila, no al montón. Esa es la razón por la que necesita un valor –

+0

Y las clases se inicializan en el montón ¿no? Y no construye. ¿Correcto? – Snake

+0

Pero el código se ejecuta en el contexto del Constructor –

Respuesta

32

No, las variables locales no tienen un valor predeterminado . Tienen que ser definitivamente asignados antes de leerlos. Esto reduce la probabilidad de que use una variable que piensa que le ha dado un valor razonable, cuando en realidad tiene algún valor predeterminado. Esto no se puede hacer, por ejemplo, ni con variables estáticas porque no sabe en qué orden se llamarán los métodos.

Consulte la sección 5.3 de la especificación C# 3.0 para obtener más detalles sobre la asignación definitiva.

Tenga en cuenta que esto no tiene nada que ver con que se trata de una variable de tipo de referencia. Esto dejará de recopilar de la misma manera:

int i; 
if (i == 0) // Nope, i isn't definitely assigned 
{ 
} 

En lo que se refiere a la lengua, de todos modos ... claramente la ubicación de almacenamiento en la memoria tiene algo en él, pero es irrelevante y específico de la implementación. Hay uno manera en que puede averiguar cuál es ese valor, creando un método con un parámetro out pero luego usando IL para ver el valor de ese parámetro dentro del método, sin darle otro valor. El CLR no le importa eso en absoluto. A continuación, puede llamar al que pasa el método en una variable no asignada definitivamente, y he aquí que puede detectar el valor, que básicamente es el valor de "todos los ceros".

Sospecho que la especificación CLI hace hacer cumplir las variables locales que tienen un valor predeterminado, pero tendría que comprobar. A menos que estés haciendo cosas malas como la anterior, no debería importarte en C#.

+6

Está controlado por la marca * localsinit * en los metadatos del método. Ver Partición III sección 3.47 "localloc" para más detalles. Me parece recordar que el CLR siempre inicializa la memoria de la pila a cero. ¿O quizás siempre lo hace cuando se conecta un depurador? No estoy seguro. En cualquier caso, los lugareños observaron en su estado no inicializado a través de medios engañosos que casi siempre parecen tener sus valores predeterminados. –

2

Las variables locales no tienen asignado un valor predeterminado. Tienes que inicializarlos antes de usarlos. Puede inicializar explicityly a null sin embargo:

public Foo() 
{ 
    Bar bar = null; 
    if (null == bar) 
    { 

    } 
} 
7

campos (variables en clases/estructuras) se inicializan a null/cero/etc. Variables locales ... bueno, ya que (por "asignación definida") no puede acceder a ellas sin asignarlas, no hay una forma sensata de responder; simplemente, no está definido ya que es imposible. Creo que suceden como null/zero/etc (demostrable mediante la piratería de algunos códigos out a través de la generación dinámica de IL), pero ese es un detalle de la implementación.


Para información, aquí hay un código crafy que muestra el valor de una variable sin inicializar formalmente:

using System; 
using System.Reflection.Emit; 
static class Program 
{ 
    delegate void Evil<T>(out T value); 
    static void Main() 
    { 
     MakeTheStackFilthy(); 
     Test(); 
    } 
    static void Test() 
    { 
     int i; 
     DynamicMethod mthd = new DynamicMethod("Evil", null, new Type[] { typeof(int).MakeByRefType()}); 
     mthd.GetILGenerator().Emit(OpCodes.Ret); // just return; no assignments 
     Evil<int> evil = (Evil<int>)mthd.CreateDelegate(typeof(Evil<int>)); 
     evil(out i); 
     Console.WriteLine(i); 
    } 
    static void MakeTheStackFilthy() 
    { 
     DateTime foo = new DateTime(); 
     Bar(ref foo); 
     Console.WriteLine(foo); 
    } 
    static void Bar(ref DateTime foo) 
    { 
     foo = foo.AddDays(1); 
    } 
} 

La IL simplemente realiza una "ret" - nunca se asigna nada.

+0

No me había dado cuenta de que había encontrado la manera de determinar el valor usando un parámetro de salida también; lo acababa de agregar a mi respuesta. Malvado, desagradable. –

+0

No sé si esta es una pregunta estúpida, pero ¿por qué el comportamiento es diferente para los campos en comparación con las variables locales? ¿Es por alcance, es decir, una variable local solo es válida dentro de una función? ¿O hay otra razón? –

+1

@Jon - ni siquiera necesitas eso; si tiene un tipo de delegado que está "fuera de su valor de YourType", simplemente cree un 'DynamicMethod' con IL =" ret ", llame a' CreateDelegate' e invoque al delegado "out myVariable". Luego inspecciona la variable. No es necesario hacer el trabajo duro en el método dinámico. –

1

Las variables locales no tienen asignado un valor predeterminado, ni siquiera un null.

1

No, las variables locales no se establecen automáticamente en 0 (valor predeterminado).

Pero debido a que (siempre) obtienes ese error, realmente no importa. Si tuviera otro valor, el compilador nunca te dejaría averiguarlo.

No confundir con las variables de campo (miembros de la clase), son inicializados al valor predeterminado de su tipo (0/null/false/...).

1

El valor de bar no está definido. Hay espacio asignado para él en la pila, pero el espacio no se inicializa a ningún valor, por lo que contiene todo lo que estaba allí antes.

(La variable local sin embargo podría ser optimizado para utilizar un registro en lugar de espacio de pila, pero aún no definido.)

El compilador no le permitirá utilizar el valor indefinido, tiene que ser capaz de determinar que la variable se inicializa antes de poder usarla.

Como comparación, VB inicializa las variables locales. Si bien esto puede ser práctico a veces, también puede significar que usted usa involuntariamente una variable antes de darle un valor significativo, y el compilador no puede determinar si eso es lo que ha dicho o no.

0

No importa, porque ningún compilador que implemente C# debe compilar dicho código.

Si hubiera un valor predeterminado, entonces sería compilable. Pero no hay ninguno para las variables locales.

0

Además de la "corrección", la inicialización de la variable local también está relacionada con el proceso de verificación del CLR.
Para obtener más detalles, vea mi respuesta a esta pregunta similar: Why must local variables have initial values

Cuestiones relacionadas