Définir deux fois une propriété dans un enregistrement

Dec 02 2020

En C # 9, on peut définir une propriété avec le même nom dans un enregistrement à la fois dans son constructeur principal et dans son corps:

record Cat(int PawCount)
{
    public int PawCount { get; init; }
}

Ce code se compile sans erreur.

Lors de l'initialisation d'une instance d'un tel enregistrement, la valeur fournie au constructeur est complètement ignorée:

Console.WriteLine(new Cat(4));
Console.WriteLine(new Cat(4) { PawCount = 1 });

impressions

Cat { PawCount = 0 }
Cat { PawCount = 1 }

Ce comportement est-il correct ou s'agit-il d'un bogue? Si c'est correct, quels sont les cas dans lesquels c'est utile?

Je m'attendais à ce que le compilateur rejette ce code avec une erreur telle que «Le type Catcontient déjà une définition pour PawCount» ou considère la propriété dans le constructeur et dans le corps de la même manière, en effectuant son initialisation à partir du constructeur. Cette dernière variante pourrait être utile pour fournir à la propriété un getter et / ou un initialiseur personnalisé sans avoir à réécrire toutes les propriétés de l'enregistrement de position dans son corps.

Le comportement réel n'a aucun sens pour moi.

Réponses

9 YairHalberstadt Dec 02 2020 at 22:10

La bonne façon de procéder est:

record Cat(int PawCount)
{
    public int PawCount { get; init; } = PawCount;
}

Ceci est utile car cela vous permet de faire par exemple la validation

record Cat(int PawCount)
{
    private int _pawCount;
    public int PawCount {
        get => _pawCount;
        init => _pawCount = value < 0 ? throw new ArgumentException() : value; 
    } = PawCount;
}

La spécification pour cela est ici: https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/records.md#members-of-a-record-type

Les membres sont synthétisés à moins qu'un membre avec une signature «correspondante» soit déclaré dans le corps de l'enregistrement ou qu'un membre concret accessible non virtuel avec une signature «correspondante» soit hérité. Deux membres sont considérés comme identiques s'ils ont la même signature ou s'ils sont considérés comme «masqués» dans un scénario d'héritage.

Ainsi, comme une propriété portant le même nom que le paramètre existe déjà, le compilateur ne synthétisera pas une PawCountpropriété, et ignore donc le paramètre en silence, sauf si vous l'utilisez vous-même explicitement.