2010-09-09 15 views
26

que he hecho un poco de búsqueda y creo que el siguiente código está garantizado para producir una salida:¿El orden de inicialización de clase estática en C# es determinista?

BX = 7

BX = 0

AX = 1

A = 1, B = 0

static class B 
{ 
    public static int X = 7; 
    static B() { 
     Console.WriteLine("B.X = " + X); 
     X = A.X; 
     Console.WriteLine("B.X = " + X); 
    } 
} 

static class A 
{ 
    public static int X = B.X + 1; 
    static A() { 
     Console.WriteLine("A.X = " + X); 
    } 
} 

static class Program 
{ 
    static void Main() { 
     Console.WriteLine("A = {0}, B = {1}", A.X, B.X); 
    } 
} 

He corrido esto varias veces y siempre obtengo el resultado por encima de la sección del código; Solo quería verificar que nunca cambiara? Incluso si textualmente, la clase A y la clase B se reorganizan?

¿Está garantizado que el primer uso de un objeto estático desencadenará la inicialización de sus miembros estáticos, seguido de la creación de instancias de su constructor estático? Para este programa, el uso de A.X en main activará la inicialización de A.X, que a su vez inicializa B.X, luego B() y luego de finalizar la inicialización de A.X, pasará a A(). Finalmente Main() generará A.X y B.X.

+0

Si Principal() había utilizado BX primero, a continuación, los valores de salida serían 7, 8, 8, A = 8, B = 8. – Jess

+2

Para el código específico dado en su pregunta, entonces la respuesta de Porges es correcta en el dinero. Para la pregunta más general de su título: * "¿Es determinístico el orden de inicialización de clases estáticas en C#?" *, La respuesta es que depende: si los tipos estáticos implicados tienen constructores estáticos, el orden de inicialización * es * determinista ; si no lo hacen, entonces no lo es. – LukeH

+0

Relacionado: http://stackoverflow.com/questions/1494735/initialization-order-of-static-fields-in-static-class –

Respuesta

31

Directamente desde ECMA-334:

17.4.5.1: "Si existe un constructor estático (§17.11) en la clase, la ejecución de los inicializadores de campo estático se produce inmediatamente antes de ejecutar que estático constructor. De lo contrario, los inicializadores de campo estático se ejecutan en un tiempo dependiente de la implementación antes de la primera utilización de un campo estático de la clase "

Y:.

17,11: La ejecución de un constructor estático es disparado por la primera de los siguientes eventos a ocurrir dentro de un dominio de aplicación:.

  • una instancia de la clase se crea
  • Se hace referencia a cualquiera de los miembros estáticos de la clase.

Si una clase contiene el método Main (§10.1) en el que comienza la ejecución, el constructor estático para esa clase ejecuta antes de llamar al método Main. Si una clase contiene campos estáticos con inicializadores, esos inicializadores se ejecutan en orden textual inmediatamente antes de ejecutar el constructor estático (§17.4.5).

Así que el orden es:

  • A.X utilizarse, por lo static A() llamada.
  • A.X debe inicializarse, pero usa B.X, por lo que static B() llamado.
  • B.X tiene que ser inicializado, y se inicializan a 7. B.X = 7
  • Todos los campos estáticos de B se inicializan, por lo que se llama static B(). X se imprime ("7"), luego se establece en A.X. A ya ha comenzado a inicializarse, por lo que obtenemos el valor de A.X, que es el valor predeterminado ("cuando se inicializa una clase, todos los campos estáticos en esa clase se inicializan primero a su valor predeterminado"); B.X = 0, y está impreso ("0").
  • Hecho inicializando B, y el valor de A.X se establece en B.X+1. A.X = 1.
  • Todos los campos estáticos de A se inicializan, por lo que se llama a static A(). A.X está impreso ("1").
  • Atrás en Main, se imprimen los valores de A.X y B.X ("1", "0").

En realidad Comentario Al hacer esto en la norma:

17.4.5:Es posible que los campos estáticos con inicializadores de variables que deben ser observadas en su estado valor predeterminado. Sin embargo, esto se desaconseja fuertemente como una cuestión de estilo.

0

La inicialización determinística de los miembros estáticos está garantizada ... pero no está en "orden de texto". Además, es posible que no se realice de forma totalmente perezosa (es decir, solo cuando se hace referencia por primera vez a la variable estática). Sin embargo, en su ejemplo con números enteros, no haría la diferencia.

En algunos casos, es deseable obtener una inicialización lenta (particularmente con Singleton costosos) - en cuyo caso a veces tiene que jump through some hoops para hacerlo bien.

+1

Debido a la referencia circular entre la inicialización de 'A' y' B' la pereza no afecta La salida. –

+1

En realidad, los inicializadores de campo estáticos se ejecutan en orden textual: stackoverflow.com/a/3681278/616827 – Jeff

6

En esta garantía están involucradas cuatro reglas diferentes en la especificación de C#, y es específica de C#. La única garantía hecha por el tiempo de ejecución de .NET es que la inicialización de tipos comienza antes de que se use el tipo.

  • Los campos estáticos se inicializan en cero hasta que se ejecuta el inicializador de tipo.
  • Los inicializadores de campo estáticos se ejecutan inmediatamente antes del constructor estático.
  • Que los constructores estáticos se llaman en la primera llamada de constructor de instancia o en la primera referencia de miembro estático.
  • Los argumentos de la función se evalúan en orden de izquierda a derecha.

Confiar en esto es una muy mala idea porque puede confundir a cualquiera que lea su código, especialmente si están familiarizados con lenguajes con una sintaxis similar que no hacen las cuatro garantías anteriores.

Tenga en cuenta que el comentario de Porges estaba relacionado con mi afirmación inicial (basada en el comportamiento de .NET) de que las garantías son demasiado débiles para garantizar el comportamiento observado. Porges tiene razón en que las garantías son lo suficientemente fuertes, pero en realidad se trata de una cadena mucho más compleja de lo que sugiere.

+3

No es verdadero. Lea 17.4.5.1: "[Si existe un constructor estático (§17.11) en la clase, la ejecución de los inicializadores de campo estáticos se produce inmediatamente antes de ejecutar el constructor estático .] De lo contrario, los inicializadores de campo estáticos se ejecutan en una implementación. tiempo dependiente anterior a el primer uso de un campo estático de esa clase. " La inicialización del campo estático solo se define en la implementación si no tiene un constructor estático. – porges

1

Le puede interesar saber que incluso es posible asignar valores a un campo entre su inicialización predeterminada y la inicialización de la variable.

private static int b = Foo(); 
    private static int a = 4; 

    private static int Foo() 
    { 
     Console.WriteLine(a); 
     a = 3; 
     Console.WriteLine(a); 
     return 2; 
    } 

    public static void Main() 
    { 
     Console.WriteLine(a); 
    } 

salidas

0 
3 
4 
Cuestiones relacionadas