Les propriétés et les structures automatiques ne se mélangent pas?

En contournant certaines petites structures tout en répondant à ce message , je suis tombé sur ce qui suit:

La structure suivante, utilisant un champ int, est parfaitement légale:

struct MyStruct { public MyStruct ( int size ) { this.Size = size; // <-- Legal assignment. } public int Size; } 

Cependant, la structure suivante, utilisant une propriété automatique, ne comstack pas:

 struct MyStruct { public MyStruct ( int size ) { this.Size = size; // <-- Compile-Time Error! } public int Size{get; set;} } 

L’erreur renvoyée est “L’object ‘this’ ne peut pas être utilisé avant que tous ses champs soient affectés à”. Je sais que c’est une procédure standard pour une structure: le champ de sauvegarde de toute propriété doit être assigné directement (et non via l’accesseur d’ensemble de la propriété) depuis le constructeur de la structure.

Une solution consiste à utiliser un champ de sauvegarde explicite:

 struct MyStruct { public MyStruct(int size) { _size = size; } private int _size; public int Size { get { return _size; } set { _size = value; } } } 

(Notez que VB.NET n’aurait pas ce problème, car dans VB.NET, tous les champs sont automatiquement initialisés à 0 / null / false lors de la création initiale.)

Cela semble être une limitation malheureuse lors de l’utilisation de propriétés automatiques avec des structures en C #. En pensant conceptuellement, je me demandais si ce ne serait pas un endroit raisonnable pour qu’il y ait une exception permettant d’appeler l’accesseur de jeu de propriétés dans le constructeur d’une structure, au moins pour une propriété automatique?

Ceci est un problème mineur, presque une affaire de bord, mais je me demandais ce que les autres pensaient de cela …

A partir de C # 6: ce n’est plus un problème


En devenant C # 6, vous devez appeler le constructeur par défaut pour que cela fonctionne:

 public MyStruct(int size) : this() { Size = size; } 

Un problème plus important est que vous avez une structure mutable. Ce n’est jamais une bonne idée. Je le ferais:

 public int Size { get; private set; } 

Pas techniquement immuable, mais assez proche.

Avec les versions récentes de C #, vous pouvez améliorer ceci:

 public int Size { get; } 

Cela ne peut maintenant être atsortingbué qu’au constructeur.

Vous pouvez résoudre ce problème en appelant d’abord le constructeur par défaut:

 struct MyStruct { public MyStruct(int size) : this() { this.Size = size; // <-- now works } public int Size { get; set; } } 

Un autre travail obscur sur ce problème est celui de la classe Tuple temporaire dans la structure d’extensibilité gérée (via Krzysztof Koźmic ):

 public struct TempTuple { public TempTuple(TFirst first, TSecond second) { this = new TempTuple(); // Kung fu! this.First = first; this.Second = second; } public TFirst First { get; private set; } public TSecond Second { get; private set; } 

(Code source complet de Codeplex: Tuple.cs )

Je note également que la documentation de CS0188 a été mise à jour pour append:

Si vous voyez cette erreur lorsque vous essayez d’initialiser une propriété dans un constructeur struct, la solution consiste à modifier le paramètre constructeur pour spécifier le champ de sauvegarde au lieu de la propriété elle-même. Les propriétés implémentées automatiquement doivent être évitées dans les structures car elles ne contiennent aucun champ de sauvegarde et ne peuvent donc pas être initialisées de quelque manière que ce soit par le constructeur.

Je suppose donc que cela signifie que les instructions officielles consistent à utiliser des propriétés de style ancien dans vos structures lorsque vous rencontrez ce problème, qui est probablement moins obscur (et plus lisible) que l’une des deux autres solutions envisagées.