2011-01-19 16 views
28

Ho scavato intorno a SO per una risposta a questo, e il migliore che riesco a trovare finora è here, tuttavia è orientato verso le istanze con costruttori statici; Sto solo usando la classe in modo statico.Eccezione nel costruttore statico

Il mio codice:

public static class MailHelper { 

    private static string mailHost; 

    static MailHelper() { 

     var mailSettings = ConfigurationManager.GetSection("MailSettings") as NameValueCollection; 
     if (null == mailSettings) { 
      throw new ConfigurationErrorsException("Missing Mail Settings in the configuration file"); 
     } 

     mailHost = ConfigurationManager.AppSettings["mailHost"]; 
     if (null == mailHost) { 
      throw new ConfigurationErrorsException("Missing mailHost setting in the configuration file"); 
     } 

    } 

    public static void SendMail(MailMessage Message) { 
     ... 
    } 

} 


try { 
    MailHelper.SendMail(Message); 
} 
catch (ConfigurationErrorsException exc) { 
    ... 
} 

// ???  
MailHelper.SendMail(Message); 


. 

Quindi, se il costruttore statico genera un'eccezione per la prima volta si chiama, quello che succede la seconda volta che provo ad accedere al metodo statico SendMail()?

PS: Ci scusiamo se non ti piace la versione di Stroustrup di K & R parentesi graffa, ma non modificare il mio post solo per cambiare le parentesi graffe al tuo stile preferito Allman. Grazie.

+0

Dovrebbe fallire, ma cosa c'è di sbagliato nel provarlo da solo? –

+0

Non penso che abbia senso lanciare da un costruttore (statico), perché la classe è in uno stato instabile (non completamente inizializzato). Che ne dici di creare una funzione esplicita 'Init()' che chiami prima dell'uso (non dovrebbe fare nulla se è già inizializzata), e se lancia un'eccezione, * non usare la classe * – Cameron

+0

Pontus> Pensavo che Jon potesse aver bisogno di qualche più punti:) –

risposta

22

Le altre due risposte sono buone risposte alla tua domanda diretta - qui è un metaanswer - si dovrebbe essere buttare l'eccezione nel metodo in cui si rileva che gli elementi di configurazione non sono popolato, piuttosto che nel costruttore. IMHO, "non configurato" è uno stato di configurazione valido per quegli elementi nella fase di costruzione, ma non al momento SendMail. Ciò aggirerà l'intero problema.

+0

+1, prospettiva interessante –

+1

Jon in realtà ha risposto alla mia domanda più correttamente, ma questa risposta propone una soluzione migliore di quella che ho. –

81

Una volta che un inizializzatore di tipo ha fallito una volta, non viene mai ripetuto. Il tipo è morto per la durata di AppDomain. (Si noti che questo è vero per tutti gli inizializzatori di tipo, non solo per i tipi con costruttori statici.Un tipo con variabili statiche con espressioni di inizializzazione, ma senza costruttori statici, può mostrare sottili differenze nei tempi dell'esecuzione dell'inizializzatore di tipo - ma sarà ancora solo accadere una volta)

Dimostrazione:.

using System; 

public sealed class Bang 
{ 
    static Bang() 
    { 
     Console.WriteLine("In static constructor"); 
     throw new Exception("Bang!"); 
    } 

    public static void Foo() {} 
} 

class Test 
{ 
    static void Main() 
    { 
     for (int i = 0; i < 5; i++) 
     { 
      try 
      { 
       Bang.Foo(); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.GetType().Name); 
      } 
     } 
    } 
} 

uscita:

In static constructor 
TypeInitializationException 
TypeInitializationException 
TypeInitializationException 
TypeInitializationException 
TypeInitializationException 

Come si può vedere, il costruttore statico viene chiamato una sola volta.

+4

È interessante notare che si prende solo 'TypeInitializationExceptions' quando si lancia esplicitamente' Exception' ... che 'Exception' viene ingoiato? –

+7

@James B: No, si trova nella InnerException di TypeInitializerException. –

+0

Ah! Spero non ti dispiaccia, ho assegnato la risposta a Chris ... La tua domanda in realtà risponde alla domanda che stavo ponendo ed è stata la più utile per capire il comportamento previsto, ma mi è piaciuta la sua soluzione per evitare i problemi con il mio approccio. Catching TypeInitializationExceptions ovunque io faccia chiamate statiche alla mia classe non sembra divertente! Grazie per l'aiuto! –

Problemi correlati