Question

Déboucher sur de petites structures tout en répondant à ce message , je suis tombé sur un message inattendu:

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 compile pas:

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

    public int Size{get; set;}
}

L'erreur renvoyée est "L'objet 'this' ne peut pas être utilisé avant que tous ses champs soient affectés à". Je sais qu'il s'agit d'une procédure standard pour une structure: le champ de sauvegarde de toute propriété doit être affecté 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 leur création.)

Cela semblerait être une limite 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 à l'accesseur de jeu de propriétés d'être appelé dans le constructeur d'un struct, au moins pour une propriété automatique?

Il s’agit d’un problème mineur, presque un cas extrême, mais je me demandais ce que les autres en pensaient ...

Était-ce utile?

La solution

À partir de la version 6, ce n'est plus un problème

Becore 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 ici 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 suffisamment proche.

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

public int Size { get; }

Ceci peut maintenant seulement être attribué dans le constructeur.

Autres conseils

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; }
}

Une autre solution obscure à ce problème est celle qui est détectée dans la classe temporaire Tuple dans Cadre d'extensibilité géré (via Krzysztof Ko & # 378; mic ):

public struct TempTuple<TFirst, TSecond>
{
    public TempTuple(TFirst first, TSecond second)
    {
        this = new TempTuple<TFirst, TSecond>(); // 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 remarque également que la documentation de CS0188 a été mise à jour pour ajouter:

  

Si vous voyez cette erreur en essayant de   initialiser une propriété dans une structure   constructeur, la solution est de changer   le paramètre constructeur à spécifier   le champ de support au lieu du   la propriété elle-même. Implémenté automatiquement   les propriétés doivent être évitées   structs parce qu'ils n'ont pas de soutien   domaine et ne peut donc pas être   initialisé en aucune façon de la   constructeur.

Donc, je suppose que cela signifie que le guide officiel consiste à utiliser des propriétés de style ancien dans vos structs lorsque vous rencontrez ce problème, qui est probablement moins obscur (et plus lisible) que l'une ou l'autre des deux autres alternatives explorées, loin.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top