- Les structures en C# sont amusantes
- Brève introduction aux Value Types vs Reference Types.
- Initialisation des champs dans les structures.
- Comportement des constructeurs dans structures (cet post).
- Des autres scénarios dans lesquels le comportement des constructeurs de structure peut vous surprendre.
- Struct avec des valeurs d'argument par défaut dans les constructeurs, ou, n'êtes-vous pas encore confus ?
- Le modificateur `required`de C # 11 ne sauvegardera pas votre
c*lemploi. - Structure utilisée comme valeurs d'argument défaut.
- Bonus: L'evolution des structures en C#
Dans le post précédent de notre série sur les Value Types, nous avons présenté le code ci-dessous:
qui imprime 0 (par opposition à 32 comme certains pourraient s'y attendre) et a également exploré les bases de la gestion de l'initialisation des champs en C#. Cet article élargit cette discussion en explorant certains aspects clés qui contribuent à la disparité entre le comportement attendu/observé.
Commençons par la déclaration suivante du post précédent:
D'une manière trop simpliste, chaque fois que le compilateur C# trouve une initialisation de champ, il déplacera simplement le code d'initialisation vers les constructeurs, c'est-à-dire que l'initialisation d'un champ équivaut à définir sa valeur dans les constructeurs (les champs statiques sont initialisés dans les constructeurs statiques)...
Si cela est vrai (spoiler : c'est le cas) et que le code instancie une nouvelle structure (ligne 1), pourquoi le champ n'est-il pas initialisé ? La réponse courte est que malgré l'expression new, aucun constructeur n'est exécuté, ce qui peut être facilement vérifié en examinant le il généré ci-dessous:
Notez que l'expression 'new S2()' a été compilée comme l'instruction IL intobj S2 (IL_0002 dans la méthode '<Main>$' mise en évidence dans la capture d'écran ci-dessus). La documentation de cette instruction indique1:
Initialise tous les champs du type de valeur figurant à l'adresse spécifiée en utilisant la référence null ou la valeur 0 du type primitif qui convient...
Contrairement à Newobj, initobj n’appelle pas la méthode du constructeur. Initobj est destiné à l’initialisation des types de valeurs, tandis qu’il newobj est utilisé pour allouer et initialiser des objets.
nous conduisant à la question suivante, naturelle : pourquoi le compilateur a-t-il émis une instruction initobj au lieu d'une newobj?
Si vous prêtez une attention particulière à la déclaration de la structure S2 (lignes 5 à 9), vous remarquerez qu'il n'y a en fait aucun constructeur sans paramètre déclaré, donc la réponse à cette question devient claire : parce que le compilateur ne peut pas invoquer un constructeur non existant, et pour les Value Types, il peut recourir à initobj à la place!
Pour prouver ce point, vous pouvez simplement modifier le code en introduisant un constructeur sans paramètre dans S22:
et observez que maintenant IL_0002 contient l'instruction call instance void S2::.ctor() exécutant effectivement le constructeur sans paramètre sur s2 et d'où, exécutant l'initialisation du champ et provoquant la sortie du programme 32.
Donc en résumé :
- Les initialiseurs de champ sont injectés dans les constructeurs du type dans lequel le champ est déclaré ;
- Puisqu'aucun constructeur n'est exécuté, tous les champs de structure sont simplement mis à zéro, ce qui explique pourquoi le programme en haut imprime zéro au lieu de 32.
Comme toujours, tous les commentaires sont bienvenus.
Amuse toi!
2. Jusqu'à la version 10, C# n'autorisait pas les structures à avoir des constructeurs explicites sans paramètre.
3. En savoir plus sur les ctors en C#