2011-01-19 24 views
28

He buscado alrededor de SO para obtener una respuesta a esto, y la mejor que puedo encontrar hasta ahora es here, sin embargo, está dirigida a instancias con constructores estáticos; Solo estoy usando la clase estáticamente.Excepción en el constructor estático

Mi código:

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


. 

Así que si el constructor estático produce una excepción de la primera vez que se llama, lo que sucede la segunda vez que intento acceder al método estático SendMail()?

PD: Disculpe si no le gusta la versión de Stroustrup de K & R, pero no edite mi publicación solo para cambiar las llaves de su estilo Allman preferido. Gracias.

+0

Debería fallar, pero ¿qué hay de malo en probarlo usted mismo? –

+0

No creo que realmente tenga sentido lanzar desde un constructor (estático), porque entonces la clase está en un estado inestable (no se ha inicializado por completo). ¿Qué tal crear una función 'Init()' explícita a la que llame antes de usarla (no debería hacer nada si ya se ha inicializado), y si arroja una excepción, * no use la clase * – Cameron

+0

Pontus> Pensé que Jon podría necesitar alguna más puntos:) –

Respuesta

22

Las otras dos respuestas son buenas respuestas a su pregunta directa - aquí hay un metaanswer - usted debe ser tirar la excepción en el método cuando se detecta que los elementos de configuración no son poblado, en lugar de en el constructor. En mi humilde opinión, "no configurado" es un estado de configuración válido para esos elementos en la fase de constructor, simplemente no en la hora SendMail. Eso soslayará todo este problema.

+0

+1, perspectiva interesante –

+1

Jon en realidad respondió mi pregunta de la manera más correcta, pero esta respuesta propone una solución mejor que la que tengo. –

81

Una vez que un inicializador de tipo ha fallado una vez, nunca se vuelve a intentar. El tipo está muerto durante toda la vida del AppDomain. (Tenga en cuenta que esto es cierto para todos los inicializadores de tipo, no solo para los tipos con constructores estáticos. Un tipo con variables estáticas con expresiones de inicializador, pero no con constructores estáticos, puede presentar sutiles diferencias en el tiempo de ejecución del inicializador de tipo, pero sí siendo sólo ocurrirá una vez)

demostración:.

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

salida:

In static constructor 
TypeInitializationException 
TypeInitializationException 
TypeInitializationException 
TypeInitializationException 
TypeInitializationException 

Como se puede ver, el constructor estático sólo se llama una vez.

+4

Es interesante que capture solo 'TypeInitializationExceptions' cuando expulsa' Exception' explícitamente ... ¿se traga esa 'Exception'? –

+7

@James B: No, está en la InnerException de TypeInitializerException. –

+0

¡Ah! Espero que no te importe, le concedí la respuesta a Chris ... Tu pregunta en realidad responde a la pregunta que hice y fue la más útil para entender el comportamiento esperado, pero me gustó su solución para evitar los problemas con mi enfoque. La captura de TypeInitializationExceptions en todas partes en las que hago llamadas estáticas a mi clase ¡no suena como diversión! ¡Gracias por tu ayuda! –

Cuestiones relacionadas