Domanda Variabile non inizializzata in C #


Ho il seguente codice:

class Foo
{

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

        }
    }
}

class Bar { }

I guru del codice vedranno già che questo dà un errore. La barra potrebbe non essere inizializzata prima dell'istruzione if.

Quindi ora mi chiedo: qual'è il bar del bar, non dovrebbe essere nullo? Non sono impostati su null? (Nullpointer?)


16
2018-03-25 13:23


origine


risposte:


No, le variabili locali non hanno un valore predefinito1. Devono essere sicuramente assegnato prima di leggerli Questo riduce la possibilità che tu usi una variabile tu pensare hai dato un valore ragionevole a, quando in realtà ha un valore predefinito. Questo non può essere fatto per esempio o variabili statiche perché non sai in quale ordine verranno chiamati i metodi.

Vedere la sezione 5.3 delle specifiche C # 3.0 per ulteriori dettagli sull'assegnazione definitiva.

Si noti che questo non ha nulla a che fare con questo essendo una variabile di tipo di riferimento. Questo non riuscirà a compilare allo stesso modo:

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

1 Per quanto riguarda la lingua, comunque ... chiaramente la posizione di memoria in memoria ha qualcosa in esso, ma è irrilevante e specifico per l'implementazione. C'è uno in che modo puoi scoprire che cos'è questo valore, creando un metodo con un out parametro ma poi usando IL per vedere il valore di quel parametro all'interno del metodo, senza averlo dato un altro valore. Il CLR non gli dispiace affatto. Puoi quindi chiamata quel metodo che passa in una variabile non assegnata definitivamente, ed ecco che potete rilevare il valore - che è probabilmente il valore di "tutti gli zeri" in pratica.

Sospetto che le specifiche CLI fa imporre le variabili locali con un valore predefinito - ma dovrei controllare. A meno che tu non stia facendo cose cattive come sopra, non dovrebbe interessarti in C #.


33
2018-03-25 13:25



I campi (variabili su classi / strutture) sono inizializzati su null/ Zero / etc. Variabili locali ... beh - dal momento che (per "assegnazione definita") non è possibile accedervi senza assegnare non c'è un modo ragionevole di rispondere; semplicemente, non è definito poiché è impossibile. Io ci credo accadere essere null/ zero / etc (dimostrabile tramite l'hacking di alcuni out codice tramite generazione di IL dinamica), ma questo è un dettaglio di implementazione.


Per informazioni, ecco un codice furbo che mostra il valore di una variabile formalmente non inizializzata:

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);
    }
}

L'IL appena fa un "ret" - non assegna mai nulla.


8
2018-03-25 13:25



Le variabili locali non vengono assegnate a un valore predefinito. Devi inizializzarli prima di usarli. È possibile inizializzare in modo esplicito a null anche se:

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

    }
}

2
2018-03-25 13:25



Alle variabili locali non viene assegnato un valore predefinito, nemmeno a null.


1
2018-03-25 13:26



No, le variabili locali non vengono automaticamente impostate su 0 (impostazione predefinita).

Ma poiché tu (sempre) ricevi questo errore, non importa. Se avesse un altro valore, il compilatore non ti permetterebbe mai di scoprirlo.

Da non confondere con le variabili di campo (membri della classe), loro siamo inizializzato al valore predefinito del loro tipo (0 / null / falso / ...).


1
2018-03-25 13:26



Il valore di bar è indefinito. Lo spazio è allocato nello stack, ma lo spazio non è inizializzato su alcun valore, quindi contiene qualcosa che prima era presente.

(La variabile locale potrebbe tuttavia essere ottimizzata per utilizzare un registro invece dello spazio di stack, ma è ancora indefinito.)

Il compilatore non ti permetterà di usare il valore non definito, deve essere in grado di determinare che la variabile sia inizializzata prima che tu possa usarla.

Come confronto, VB inizializza le variabili locali. Anche se a volte può essere pratico, può anche significare che tu usi una variabile in modo non manuale prima che tu gli abbia dato un valore significativo, e il compilatore non può determinare se è ciò che hai indotto a fare o meno.


1
2018-03-25 13:27



Non importa perché nessun codice dovrebbe essere compilabile da qualsiasi compilatore che implementa C #.

Se esistesse un valore predefinito, sarebbe compilabile. Ma non ce n'è per le variabili locali.


0
2018-03-25 13:28



Oltre alla "correttezza", l'inizializzazione della variabile locale è anche correlata ai CLR processo di verifica.
Per maggiori dettagli, vedi la mia risposta a questa domanda simile: Perché le variabili locali devono avere valori iniziali


0
2017-08-01 18:20