2016-01-26 21 views
5

Sto cercando di capire la necessità di costruttori statici. Nessuna delle informazioni che ho trovato ha risposto alla domanda che ho. Perché si dovrebbe fare questoCercando di capire i costruttori statici

class SimpleClass 
{ 
    // Static variable that must be initialized at run time. 
    static readonly long baseline; 

    // Static constructor is called at most one time, before any 
    // instance constructor is invoked or member is accessed. 
    static SimpleClass() 
    { 
     baseline = DateTime.Now.Ticks; 
    } 
} 

al contrario di questo

class SimpleClass 
{ 
    // Static variable that must be initialized at run time. 
    static readonly long baseline = DateTime.Now.Ticks; 

    // Static constructor is called at most one time, before any 
    // instance constructor is invoked or member is accessed. 
    //static SimpleClass() 
    //{ 

    //} 
} 

?


Questo non è un problema di altra domanda, si tratta di costruttori statici che non accettano parametri.

+0

Questa non è una domanda statica specifica, la domanda è valida anche per l'inizializzazione non statica. –

+0

Possibile duplicato di [Inizializza campi di classi nel costruttore o nella dichiarazione?] (Http://stackoverflow.com/questions/24551/initialize-class-fields-in-constructor-or-at-declaration) –

+0

@CyrilGandon Che non è un dupe: si tratta di costruttori statici che non accettano parametri. Prendi in considerazione la rimozione del tag dupe. –

risposta

5

La necessità è in qualche modo ovvia: si desidera eseguire più dell'inizializzazione di alcuni campi per i membri statici.

Logicamente se si dispone di questa classe:

class SimpleClass 
{ 
    // Static variable that must be initialized at run time. 
    static readonly long baseline = DateTime.Now.Ticks; 


} 

È possibile ri-scrivere per avere lo stesso effetto:

class SimpleClass 
{ 
    // Static variable that must be initialized at run time. 
    static readonly long baseline; 

    static SimpleClass() { 
     baseline = DateTime.Now.Ticks; 
    } 
} 

Ma invece, si potrebbe fare di più nel vostro costruttore statico come ad esempio ispezionare (usando la riflessione) alcune proprietà ed emettere alcuni fast accessors/getter a loro, o semplicemente avvisare altri sistemi che il tuo tipo è stato creato, ecc.

Da J effrey Richter CLR via C# libro:

Quando il compilatore C# vede una classe con campi statici che utilizzano in linea di inizializzazione (la classe BeforeFieldInit), il compilatore emette voce di tabella di tipo definizione della classe con la bandiera metadati BeforeFieldInit . Quando il compilatore C# vede una classe con un costruttore esplicito di tipo (la classe Precise), il compilatore emette la voce della tabella di definizione del tipo senza il contrassegno dei metadati di BeforeFieldInit. La motivazione dello è la seguente: l'inizializzazione dei campi statici deve essere eseguita prima dell'accesso ai campi, mentre un costruttore di tipo esplicito può contenere codice arbitrario che può avere effetti secondari osservabili ; questo codice potrebbe dover essere eseguito in un momento preciso.

Obviouselly c'è qualcosa di più che questo avvenga dietro le quinte, vi suggerisco di leggere l'intero capitolo dal CLR via C#: "Tipo Costruttori"

+5

Beh, non sono esattamente la stessa cosa: una classe con un costruttore statico può avere tempi di inizializzazione diversi rispetto a una classe che ha solo inizializzatori di campo statici. Vedere http://csharpindepth.com/Articles/General/Beforefieldinit.aspx –

+0

puoi mostrare un esempio perché ho bisogno di un costruttore statico, cosa posso fare lì che non posso fare nell'inizializzazione di un campo? –

+0

@JonSkeet Forse è possibile rispondere a –

3

Questo è un esempio di una possibile differenza:

class SimpleClass 
{ 
    static readonly long A = DateTime.Now.Ticks; 
    static readonly long B = DateTime.Now.Ticks; 

    static SimpleClass() 
    { 
    } 
} 

A e B non sono garantiti per essere lo stesso valore, ma se si dovesse scrivere nel costruttore, si potrebbe garantirla:

class SimpleClass 
{ 
    static readonly long A; 
    static readonly long B; 

    static SimpleClass() 
    { 
     var ticks = DateTime.Now.Ticks; 
     A = ticks; 
     B = ticks; 
    } 
} 

Inoltre, l'ordine è soggetto a per l'istanziazione di membri statici.

Secondo ECMA-334 in relazione al campo di inizializzazione statico:

del campo statico initializers variabili di una dichiarazione di classe corrispondono ad una sequenza di compiti che vengono eseguiti nell'ordine testuale in cui appaiono nella dichiarazione di classe. Se nella classe è presente un costruttore statico (§17.11), l'esecuzione degli inizializzatori di campo statici si verifica immediatamente prima dell'esecuzione di tale costruttore statico . In caso contrario, gli inizializzatori campo statico sono eseguiti in un momento implementazione-dipendente prima del primo utilizzo di un campo statico di quella classe

Quindi, possiamo scrivere qualcosa del genere:

class SimpleClass 
{ 
    public static readonly long A = IdentityHelper.GetNext(); 
    public static readonly long B = IdentityHelper.GetNext(); 

    static SimpleClass() 
    { 
    } 
} 

public static class IdentityHelper 
{ 
    public static int previousIdentity = 0; 
    public static int GetNext() 
    { 
     return ++previousIdentity; 
    } 
} 

Qui, è garantito che lo A sia assegnato prima dello B. In questo esempio, A sarà 1 e B sarà 2. Possiamo garantire che A < B (presupponendo che l'identità non esca e non ci siano problemi con il threading). Ora, se noi riordinare i campi:

public static readonly long B = IdentityHelper.GetNext(); 
public static readonly long A = IdentityHelper.GetNext(); 

La funzionalità cambia. Pertanto, abbiamo creato un effetto collaterale che non è immediatamente chiaro semplicemente riordinando le definizioni dei campi.

Uno scenario più probabile è, si può decidere di fare questo:

class SimpleClass 
{ 
    public static readonly long A = IdentityHelper.GetExpensiveResult().A; 
    public static readonly long B = IdentityHelper.GetExpensiveResult().B; 

    static SimpleClass() 
    { 
    } 
} 

Qui, non siamo in grado di condividere GetExpensiveResult() tra i campi.

+0

Una piccola parte del codice che non è correlata alla domanda, 'return ++ currentIdentity' è migliore, altrimenti avrai sempre' IdentityHelper.currentIdentity == IdentityHelper.GetNext() ' –

+0

@DannyChen Hai ragione - grazie:) – Rob

+0

@Danny Chen, potresti approfondire il tuo ultimo commento; Non sono abbastanza sicuro di aver capito come funzionava –

Problemi correlati