Pourquoi en C # l’importance de l’ordre pour l’initialisation statique?

Ce code a le comportement bien défini en C # de ne pas fonctionner:

class Foo { static List to = new List( from ); // from is still null static IEnumerable from = Something(); } 

Remarque: je ne vous demande pas comment corriger ce code car je sais déjà comment le faire.

Quelle est la justification pour cela? C # effectue déjà des contrôles d’exécution pour détecter le premier access aux membres statiques. Pourquoi ne pas étendre cela à un élément par membre et le faire exécuter à la demande ou mieux, demandez au compilateur de déterminer l’ordre au moment de la compilation?

BTW: Je pense que la même question (ou presque la même) vaut également pour les membres non statiques.

Je peux envisager un programmeur en fonction de l’ordre d’initialisation en raison d’effets secondaires avec d’autres classes statiques. Vous et moi soaps tous les deux que compter sur les effets secondaires est une mauvaise pratique, mais que ce n’est pas forcément illégal.

Considérons quelque chose comme ceci:

 class Foo { static ssortingng header = Bar.GetHeader(); static ssortingng version = Bar.GetVersion(); } 

Et Bar.GetVersion suppose que Bar.GetHeader a été appelé. Si le compilateur était libre de changer l’ordre d’initialisation, le programmeur ne pourrait pas garantir l’ordre d’initialisation.

Moche, accordé, mais parfaitement légal. Si vous imaginez des effets de second ordre (c’est-à-dire des méthodes statiques qui dépendent elles-mêmes de classes ayant des effets secondaires), vous verrez qu’il est impossible pour le compilateur de réorganiser de manière fiable quoi que ce soit, tout comme il est impossible (en général) pour le compilateur de réorganiser le ordre d’appels de fonction dans votre constructeur statique.

Les initialiseurs ne sont qu’un sucre syntaxique. Le compilateur place ce code dans le fichier .cctor lors de la compilation de votre classe et les insère dans les ordres qu’ils ont mis en place dans le code.

Il n’exécute aucune vérification, car cela n’a aucun sens. Vous pouvez toujours avoir des cycles d’initialisation, de sorte que cela ne fonctionne pas de toute façon.

J’ai blogué à ce sujet il y a quelque temps si vous êtes intéressé:

  • plus sur l’initialisation en ligne
  • plus sur l’initialisation en ligne (réponse)

C # effectue des vérifications à l’exécution pour détecter le premier access à une classe, mais ne réordonne pas l’initialisation statique dans une classe.

Les champs statiques sont initialisés de haut en bas, suivis des constructeurs statiques de haut en bas. Modifiez l’ordre de vos champs ou créez un constructeur statique et initialisez les champs à partir de là.

Voir Variantes d’initialisation dans la spécification C # ou cet article sur les initialiseurs. De plus, la question Ordre des constructeurs / initialiseurs statiques en C # est liée.

Je pense que ce que vous devez utiliser est un constructeur statique.

Ainsi

 class Foo { static List to; static IEnumerable from; static Foo() { from = Something(); to = new List(from); } } 

Pour ce qui est de savoir pourquoi C # ne le fait pas lors du premier access, je ne vois tout simplement pas la nécessité de ce genre de complexité, alors qu’il existe d’autres alternatives qui permettent de clarifier ce qui se passe.