2009-09-10 16 views
8

DependencyProperty.AddOwner MSDN page ofrece un ejemplo con dos clases con miembros estáticos, y el miembro de una clase depende del miembro de la otra clase para la inicialización. Creo que MSDN está equivocado: el orden de inicialización de las variables estáticas no es confiable en C# just like it is in C++ o en otro lugar. Probablemente estoy equivocado porque la biblioteca WPF está escrita de esa manera y funciona bien. ¿Qué me estoy perdiendo? ¿Cómo es posible que el compilador de C# sepa la orden de inicialización segura?¿Cuál es el orden de inicialización de la variable estática en C#?

Respuesta

23

Está bien que un tipo dependa de que se inicialice otro tipo, siempre que no termine en un ciclo.

Básicamente esto está muy bien:

public class Child 
{ 
    static Child() {} // Added static constructor for extra predictability 
    public static readonly int X = 10; 
} 

public class Parent 
{ 
    static Parent() {} // Added static constructor for extra predictability 
    public static readonly int Y = Child.X; 
} 

El resultado está bien definido. Los inicializadores de variables estáticas Child se ejecutan antes del primer acceso a cualquier campo estático en la clase, según la sección 10.5.5.1 de la especificación.

Esto no es sin embargo:

public class Child 
{ 
    public static readonly int Nasty = Parent.Y; 
    public static readonly int X = 10; 
} 

public class Parent 
{ 
    public static readonly int Y = Child.X; 
} 

En este último caso, ya sea terminar con Child.Nasty=0, Parent.Y=10, Child.X=10 o Child.Nasty=0, Parent.Y=0, Child.X=10 dependiendo de cuál se accede a la primera clase.

Al acceder a Parent.Y first comenzará a inicializar Parent primero. La inicialización de Child se deberá dar cuenta de que Parent debe inicializarse, pero el CLR sabe que ya se está inicializando, por lo que continúa independientemente, lo que lleva al primer conjunto de números porque Child.X termina siendo inicializado antes de que su valor se use para Parent.Y.

Al acceder a Child.Nasty comenzará a inicializar Child primero, que luego comenzará a inicializar Parent. La inicialización de Parent se dará cuenta de que Child debe inicializarse, pero el CLR sabe que ya se está inicializando, por lo que continúa independientemente, lo que lleva al segundo conjunto de números.

No haga esto.


EDIT: Bueno, la explicación más detallada, como había prometido.

¿Cuándo se inicializa un tipo?

Si un tipo tiene un constructor estático, sólo se inicializará cuando se usa primero (ya sea cuando se hace referencia a un miembro estático, o cuando se crea una instancia). Si no tiene tiene un constructor estático , se puede inicializar earler. En teoría, también podría inicializarse más tarde ; en teoría, podría llamar a un constructor un método estático sin inicializar las variables estáticas, pero se debe inicializar antes de que se haga referencia a las variables estáticas.

¿Qué ocurre durante la inicialización?

Primero todas las variables estáticas reciben sus valores predeterminados (0, nulo etc.).

A continuación, las variables estáticas del tipo se inicializan en el orden textual . Si la expresión inicializador para una variable estática requiere otro tipo que ser inicializado, entonces ese otro tipo será inicializa completamente antes de que se le asigna el valor de la variable - menos que ya se está inicializando segundo tipo (debido a una dependencia cíclica ) En esencia, es un tipo cualquiera:

  • Ya inicializada
  • se inicializa en el momento
  • No inicializado

inicialización se activa sólo si el tipo no se ha inicializado. Esto significa que cuando hay dependencias cíclicas, es posible observar el valor de una variable estática antes de que su valor inicial tenga asignado. Eso es lo que muestra mi ejemplo Child/Parent.

Después de que se hayan ejecutado todos los inicializadores de variables estáticas, se ejecuta el constructor estático .

Consulte la sección 10.12 de la especificación C# para obtener más información sobre todo esto.


Por demanda popular, aquí fue mi respuesta original cuando pensaba que la pregunta era sobre el orden de inicialización de variables estáticas dentro de una clase:

Las variables estáticas se inicializan en orden textual, según apartado 10.5.5.1 de la C# spec:

el campo estático inicializadores variables de una clase corresponden a una secuencia de asignaciones que se ejecutan en elorden textual en el que aparecen en la declaración de clase.

Tenga en cuenta que los tipos parciales lo hacen más complicado ya que no hay un único "orden de texto" canónico de la clase.

+0

Gracias por su breve aparición, Most Holy. –

+0

P.S. Su primera versión de publicación tuvo información útil. Devuélvelo por favor? –

+0

@Nuevo en la ciudad: fue útil pero no relevante. Lo agregará como una nota secundaria. –

0

Si le preocupa el orden, siempre puede colocar su código en el constructor estático. Aquí es donde registro mis propiedades de dependencia.

0

No, creo que poco fiable no es la palabra correcta aquí.

En el escenario de un solo hilo verdadero, los miembros estáticos de la clase se inicializan cuando se accede por primera vez a cualquiera de los miembros estáticos del tipo en su código.

No conozco C++, pero sí solo en ciertos casos como en el entorno Multi threaded si dos tipos intentan acceder al recurso compartido y si eso es estático entonces es imposible saber quién ganará y cuál funcionará correctamente.

El ejemplo de MSDN es correcto y funcionará correctamente.

Cuestiones relacionadas