2009-04-02 11 views
18

L'inizializzazione del campo statica deve essere completata prima che venga chiamato il costruttore?Come funziona l'inizializzazione del campo statico in C#?

Il seguente programma fornisce un output che mi sembra non corretto.

new A() 
_A == null 
static A() 
new A() 
_A == A 

Il codice:

public class A 
{ 
    public static string _A = (new A()).I(); 

    public A() 
    { 
     Console.WriteLine("new A()"); 
     if (_A == null) 
      Console.WriteLine("_A == null"); 
     else 
      Console.WriteLine("_A == " + _A); 
    } 

    static A() 
    { 
     Console.WriteLine("static A()"); 
    } 

    public string I() 
    { 
     return "A"; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var a = new A(); 
    } 
} 

risposta

22

Questo è corretto.

Gli inizializzatori statici, quindi il costruttore statico viene eseguito prima del costruttore standard, ma quando viene eseguito utilizza la nuova A(), quindi passa attraverso il percorso del costruttore non statico. Questo causa i messaggi che vedi.

Ecco il percorso completo di esecuzione:

Quando prima chiamata var a = new A(); nel programma, questa è la prima volta A si accede.

Questo sparare l'inizializzazione statica di A._A

A questo punto, A._A costruisce con _A = (new A()).I();

Questo colpisce


Console.WriteLine("new A()"); 
if (_A == null) 
    Console.WriteLine("_A == null");   

poiché a questo punto, _A non e 'stato impostato con il tipo restituito, costruito (ancora).

Successivamente, viene eseguito il costruttore statico A { static A(); }. Questo stampa il messaggio "statico A()".

Infine, l'istruzione originale (var a = new A();) viene eseguita, ma a questo punto, la statica viene creata, quindi si ottiene la stampa finale.

+0

Dang! Bastonatemi! –

+0

Con tutto il rispetto ... il costruttore statico non viene eseguito per primo. L'inizializzatore del campo statico viene eseguito per primo. – Prankster

+1

La costruzione di A._A avviene nel costruttore statico. È solo che il compilatore antepone tutte le inizializzazioni dei campi nel costruttore statico (.cctor) prima del codice dichiarato nel costruttore statico C#. –

-1

Sì, l'inizializzazione dei campi statici dovrebbe essere completata prima che venga chiamato il costruttore. Ma metti il ​​compilatore nella situazione non normale e non può obbedire a questa regola.

Questo è un trucco interessante, ma non accadrà nella normale applicazione.

1

In realtà credo che stia facendo quello che pensi. Il tuo test rende difficile dirlo.

vostro inizializzazione del _A per

public static string _A = (new A()).I(); 

Prima crea una nuova istanza di A, quindi i vostri scritti di nuovo A() e _A = null. Perché era nullo quando è iniziato, poiché questa è l'inizializzazione. Una volta initalizzato, viene chiamato il costruttore statico, che restituisce la nuova istanza.

0

Sembra che il compilatore stia facendo l'attesa.

1 ° - Tutto il codice statico viene eseguito (campi costruttore, poi statica) nella classe:

public static string _A = (new A()).I(); 

// and 

static A() 
{ 
    Console.WriteLine("static A()"); 
} 

2 ° - costruttore della classe si chiama:

public A() 
{ 
    Console.WriteLine("new A()"); 
    if (_A == null) 
     Console.WriteLine("_A == null"); 
    else 
     Console.WriteLine("_A == " + _A); 
} 

Chiedete perché questo è possibile. Beh, a mio parere, un'istanza non richiede assolutamente che tutte le variabili di classe siano inizializzate al momento della creazione. Richiede solo che debbano esistere. Penso che questo caso particolare supporti questo pensiero perché viene creata un'istanza prima che venga eseguita l'inizializzazione statica.

0

Una nota lato extra - la specifica C# (sto guardando 4.0, ma è lì a 3.0 troppo) dice nel 10.5.5.1 statico campo di inizializzazione:

Se un costruttore statico (§10.12) esiste nella classe, l'esecuzione degli inizializzatori di campo statici si verifica immediatamente prima dell'esecuzione di tale costruttore statico . In caso contrario, gli inizializzatori di campo statici vengono eseguiti in un tempo dipendente dall'implementazione prima del primo utilizzo di un campo statico di quella classe.

Si dispone di un costruttore statico, pertanto la clausola "Altrimenti" non si applica. Ma penso che siano informazioni rilevanti per la tua domanda sapere che se non hai un costruttore statico, gli inizializzatori di campo statici possono essere eseguiti "in un tempo dipendente dall'implementazione". Ciò potrebbe essere importante se l'inizializzatore di campo statico sta eseguendo un tipo di inizializzazione o creazione di un oggetto su cui si basa senza accedere al campo statico stesso.

È esoterico, immagino, ma l'ho visto accadere oggi poiché il "tempo dipendente dall'implementazione" sembra essere cambiato tra C# 3.0 e 4.0 - almeno per la situazione che stavo osservando. La soluzione facile, ovviamente, è semplice: basta aggiungere un costruttore statico ...