2009-05-19 1 views
2

Avez-vous une idée, pourquoi le code suivant:Caractéristique intéressante avec les champs statiques. StackOverflow exception

public class A 
{ 
    public static int i = B.i + 1; 
} 

public class B 
{ 
    public static int i = A.i + 1; 
} 

Ayant:

 int aa = A.i; 
     int bb = B.i; 

dit que aa = 2 (!!!) et bb = 1.

J'ai un STACK OVERFLOW dans mon cerveau !!! Pour autant que je sache, la récursivité s'arrête sur les méthodes statiques, mais pourquoi? Si vous remake int i aux getters (pour déboguer et comprendre pourquoi ça fonctionne comme ça), vous obtenez l'exception de débordement de pile.

+0

Caractéristique de polymorphisme? – bzlm

+0

Je ne sais pas pourquoi cela modded vers le bas. –

Répondre

6

Aucune exécution de doute se passe comme si:

Le B.i initialiseur statique se dirige d'abord, et définit B.i = A.i + 1. Puisque A.i n'a pas encore été initialisé, A.i est égal à default(int), ce qui correspond à 0. B.i obtient la valeur 1.

L'initialiseur statique A.i s'exécute en second et définit A.i = B.i + 1 = 2. Comme les initialiseurs statiques s'exécutent dans un ordre indéfini, vous pouvez constater qu'un champ différent est 2 chaque fois que vous l'exécutez ou qu'ils changent lorsque vous apportez d'autres modifications structurelles à votre code. Cependant, on devrait toujours se terminer par 2, et on devrait toujours être 1.

P.S. Cela n'a rien à voir avec le polymorphisme.

EDIT: Pour une meilleure compréhension du calendrier des initialisations statiques et les constructeurs, vous voudrez peut-être examiner this relevant portion of the C# specification.

+0

ok il n'y a rien de commun avec le polymorphisme. mais pourquoi ne tombe-t-il pas dans l'appel récursif ??? – 0100110010101

+0

Il n'y a pas d'appel récursif (sauf si vous le modifiez pour être un getter de propriété.) Les initialiseurs de champ s'exécutent une fois et font leur chose; ils ne sont pas "appelables". – mquander

+0

Ce que je veux dire est que lorsque l'initialisateur B.i (par exemple) veut la valeur de A.i, il n'appelle pas A.i et dit "hey, calculez-vous la valeur, s'il vous plaît." Il regarde juste ce que A.i est réellement en mémoire. Avant l'initialisation de A.i, cela signifie que A.i est 0. – mquander

4

Un champ n'est pas comme un getter de propriété. Il stocke simplement les données, pas n'importe quelle opération. En fait, l'initialisation sera déplacée vers une autre méthode (constructeur statique, .cctor) qui initialisera les variables statiques de la classe.

Au début, les deux seront égal à 0. Avant d'accéder à A.i pour la première fois, la méthode .cctor pour la classe A s'exécute. Il tente d'accéder pour la première fois à B.i ce qui entraînera l'exécution du constructeur statique de la classe B. .cctor de B va essayer d'accéder A.i mais comme ce n'est pas la première fois qu'un champ est en cours d'accès, constructeur statique de A va non plus fonctionner plus. Il récupère simplement la valeur actuelle de A qui est toujours 0. Par conséquent, B.i sera égal à 1 lorsque B..cctor terminera l'exécution et le contrôle sera renvoyé à A..cctor. Il va voir la valeur B.i et ajoute 1 à celui-ci et le stocke dans A.i. Ainsi, A.i sera égal à 2 (1 + 1) et B.i sera égal à 1.

La seule garantie que vous obtenez est que le constructeur statique sera appelé avant un membre statique de cette classe est accessible.

1

Voici ce qui se passe.

  • A est accédé pour la première fois.
  • A.i est créé avec la valeur 0.
  • L'initialiseur statique pour A s'exécute.
  • B est accédé pour la première fois.
  • A.i est accédé. Il a actuellement la valeur 0.
  • Bi est réglé sur 1. Ai est réglé sur 2.

La chose vraiment importante à noter est que les propriétés statiques sont initialisés à leurs valeurs par défaut et puis statique l'initialiseur s'exécute.

Personnellement, j'évite autant que possible l'initialisation statique, l'état statique et le reste. Il y a trop de pièges.