2012-01-05 29 views
13

Tengo una clase estática con un constructor estático que toma algún tiempo (10-15 segundos) para ejecutar e inicializar completamente la clase. Para mejorar el rendimiento, he decidido permitir que esta clase estática se inicialice explícitamente en lugar de cuando se necesita por primera vez para que esté lista cuando realmente se necesite.¿Cómo inicializar una clase estática de C# antes de que realmente se necesite?

Mi primera idea era crear un método Initialize() para la clase, pero como ya tengo un constructor estático, no parece que este método tenga que hacer nada más que ser el método a llamar para inicializar explícitamente la clase sin acceder a cualquiera de sus otros métodos o propiedades públicas. Tener un método que no hace nada directamente no me parece correcto.

Luego pensé que podía mover el código del constructor estático a este método Initialize(), pero también me gustaría que la clase se inicialice cuando se necesita por primera vez y el método Initialize() no se llamó explícitamente.

En resumen, quiero que se deben observar los siguientes criterios:

  • Quiero permitir la clase estática para inicializar explícitamente (probablemente mediante el uso de un método público Initialize()).
  • No quiero tener que acceder a ningún otro método público o propiedades en la clase cuando no los necesite, aunque esto inicializaría la clase estática.
  • Si la clase no se ha inicializado explícitamente, aún quiero inicializarla cuando se necesita por primera vez (es decir, cuando se accede a otros métodos o propiedades públicas con la intención de utilizar la funcionalidad o los datos que proporcionan).
  • Esta es una clase auxiliar y el uso del patrón de diseño Singleton no es necesario para mis propósitos.

¿Cuál sería la forma correcta de observar los criterios anteriores para una clase estática escrita en C#? Esto también se puede aplicar a otros lenguajes de programación (por ejemplo, Java), pero personalmente estoy interesado en una solución escrita en C#.

+0

Por qué no inicializar la clase en el constructor estático? Creo que su deseo de poder inicializar manualmente es innecesario. – ChaosPandion

+0

http://msdn.microsoft.com/en-us/library/bb397680.aspx – Venki

+0

¿No es una clase estática "inicializable" * no * una clase estática? ¿Cuál sería el propósito de este tipo de comportamiento? Parece que desea instanciar una clase basada en valores estáticos en su lugar. –

Respuesta

14

que probablemente sólo tiene que ir para el método Initialize - y pueden hacer algo útil:

  • Se puede iniciar la sesión que se está tratando de forma explícita para inicializar la clase , con un seguimiento de la pila
  • se podría producir una excepción si la clase es ya inicializar por medio de otra llamada Initialize
  • Usted podría posiblemente (con un poco de esfuerzo y reorganización) ordene las cosas para que las excepciones causadas durante la inicialización se hayan propagado sin el TypeInitializationException que normalmente obtendría.
+0

¿Cómo puedo determinar si la clase estática ya está inicializada? No estoy usando el patrón de Singleton, así que no tengo una instancia de la clase a la que hacer referencia. El constructor estático siempre se llama antes del cuerpo del método 'Initialize()', por lo que los miembros estáticos siempre se inicializan. No veo cómo puedo hacer esto sin usar el patrón de Singleton. – Bernard

+1

@Bernard: mantendría una variable estática para decir si se había llamado primero a 'Initialize'. Tenga en cuenta la parte de la llamada "a través de otra inicialización": solo 'Initialize' establecería el valor, pero el constructor estático * probaría * si ya estaba configurado. –

+0

¡Gracias por aclarar eso! – Bernard

2

No estoy seguro de si puede especificar cuándo se carga un constructor estático.

De MSDN "Un constructor estático se llama automáticamente para inicializar la clase antes de que se cree la primera instancia o se haga referencia a cualquier miembro estático."

http://msdn.microsoft.com/en-us/library/k9x6w0hc(v=vs.80).aspx

* EDIT: * Would añadiendo la ayuda patrón singleton aquí? El getter puede llamar a Initialize() marcando un indicador en la clase, IsLoaded = true.Las llamadas posteriores no llamarán Initialize()

+0

Me doy cuenta de que no se puede llamar explícitamente a un constructor estático, pero quiero permitir que un mecanismo de la clase diga: "Sí, quiero que esta clase se inicialice ahora". a la vez que permite: "No te he inicializado, pero por favor, iniciate antes de que empiece a usarte". – Bernard

+0

El uso del patrón Singleton forzaría el uso de un método 'Initialize()' ya que necesita crear explícitamente la instancia única de la clase. Siento que no necesito mantener una instancia de esta clase porque utilizo esta clase como una clase auxiliar y no tengo la necesidad de pasarle una instancia como argumento a otros métodos de clase. – Bernard

17

Me gustaría ir con el método de inicialización (EDITAR: Ver la respuesta de Jon). Pero si realmente que desea es utilizar el constructor, puede hacer esto:

var type = typeof (YourType); 
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle); 

RunClassConstructor permite forzar el constructor de la clase (constructor estático) para ejecutar si ya no lo ha hecho. Si ya se ejecutó, digamos porque usaste un miembro estático de la clase, entonces esto no tiene ningún efecto. Ejecutarlo veces adicionales no tiene ningún efecto.

+0

Enfoque interesante. No es lo que me gustaría usar, pero es bueno saber que es una opción. – Bernard

0

El enfoque no me parece asqueroso. Podría nombrar el método Touch(), darle un cuerpo vacío y agregar un comentario apropiado. ¿Sería eso suficiente para superar su sensación de que algo no se siente bien al respecto?

+2

No realmente. Nunca pensé que diseñaría una clase con un método 'Touch()'. Se siente sucio :) – Bernard

+0

Me pregunto si escribir 'var type = typeof (ClassToInitialize);' sería suficiente, aunque no sé si se compilará. – Hatchling

2

Dos soluciones temporales:

  1. mover el código constructor para Initialize() por lo que se puede llamar de forma explícita. Y reemplazar el código dentro del constructor para simplemente llamar al método Initialize() en el caso de la clase estática se carga dinámicamente antes hemos llamado explícitamente

    public static class StaticClass 
    { 
        // actual constructor 
        static StaticClass() 
        { 
         Initialize(); 
        } 
    
        // explicit "constructor" 
        public static void Initialize() 
        { 
         MyProperty = "Some Value"; 
        } 
    
        public static string MyProperty { get; set; } 
    
    } 
    

    inicialice como esto si quieres:

    StaticClass.Initialize(); 
    

    O se inicializará dinámicamente la primera vez que se usa

  2. No es tan prístino semánticamente, pero puede desencadenar la inicialización orgánica de una clase estática simplemente consumiendo una propiedad y lanzándola de forma temporal variable.

    Así que hacer esto:

    // trigger static initilaization 
    var dummy = StaticClass.MyProperty; 
    

    Aún le permite llamar a él siempre que lo necesite, pero si hay algún costo de rendimiento en la inicialización, se puede intentar invocar que en el arranque, en lugar de la primera tiempo que el usuario hace algo que dispara ese código.

Por otro esquema útil de inicialización estática, véase: Is the order of static class initialization in C# deterministic?

Cuestiones relacionadas