Différence en C # entre les différents styles getter

154

Je vois parfois des abréviations dans les propriétés du getter. Par exemple, ces deux types:

public int Number { get; } = 0

public int Number => 0;

Quelqu'un peut-il me dire s'il y a des différences entre ces deux. Comment se comportent-ils? Les deux sont-ils en lecture seule?

WoIIe
la source

Réponses:

266

Oui, les deux sont en lecture seule, mais il y a une différence. Dans le premier, il y a un champ de sauvegarde qui est initialisé à 0 avant que le constructeur ne soit exécuté. Vous ne pouvez modifier la valeur que dans le constructeur , tout comme un champ en lecture seule normal. Le getter lui-même renvoie simplement la valeur du champ.

Dans le second, le getter renvoie simplement 0 à chaque fois, sans champ impliqué.

Donc, pour éviter d'utiliser des propriétés implémentées automatiquement ou des membres dotés d'une expression, nous avons:

Première version

private readonly int _number = 0;
public int Number { get { return _number; } }

Deuxième version

public int Number { get { return 0; } }

Un exemple plus clair de la différence pourrait être vu comme ceci:

public DateTime CreationTime { get; } = DateTime.UtcNow;
public DateTime CurrentTime => DateTime.UtcNow;

Si vous créez un seul objet, sa CreationTimepropriété donnera toujours le même résultat - car elle est stockée dans un champ en lecture seule, initialisé lors de la construction de l'objet. Cependant, chaque fois que vous accédez à la CurrentTimepropriété, cela entraînera DateTime.UtcNowune évaluation, de sorte que vous obtiendrez un résultat potentiellement différent.

Jon Skeet
la source
23
Notez que la deuxième version ne renvoie pas toujours la même valeur. Un bon exemple est si vous revenez random.NextInt(). La première version évaluera cela une fois et aura toujours la même valeur. Le second renverra une nouvelle valeur à chaque fois.
248

Une différence est quand cela 0est évalué: lors de la création de l'objet ou lorsque la propriété est utilisée.

Vous pouvez mieux voir cela avec les propriétés DateTime:

class SomeTestClass
{
    public DateTime Start { get; } = DateTime.Now;

    public DateTime Now => DateTime.Now;
}

La Startpropriété continue de renvoyer la même heure (celle de la création de l'instance), tandis qu'elle Nowchange pour refléter l'heure actuelle.

Explication :

La première version ("Start") fournit une valeur initiale qui peut même être écrasée par le constructeur. Cela n'est donc évalué qu'une seule fois.
La deuxième version ("Now") fournit l'expression qui sera le "getter" de cette propriété. Cela est donc évalué à chaque fois que la propriété est lue. Il n'y a même pas de champ de sauvegarde que le constructeur puisse écraser.

Hans Ke st ing
la source
26
C'est la distinction la plus importante à mon avis.
Matthew
14
La réponse acceptée définit le plus précisément la différence dans l'exemple de code, mais cela explique une différence plus utile dans les deux structures.
Kamil Drakari le
3
Wow, vous avez plus de votes positifs que le célèbre Jon Skeet lui-même.
machine_1
21

Ce sont des fonctionnalités du langage C # 6.

Premier exemple

public int Number { get; } = 0

Le premier exemple est une propriété automatique en lecture seule . Le champ de sauvegarde d'une propriété automatique en lecture seule est implicitement déclaré en lecture seule.

Deuxième exemple

public int Number => 0;

Et le deuxième exemple concerne les corps d'expression sur les membres de fonction de type propriété . Notez qu'il n'y a pas de getmot clé: il est impliqué par l'utilisation de la syntaxe du corps de l'expression.

Les deux sont en lecture seule.

Jehof
la source
5
... mais comme l'explique Jon Skeet, vous pouvez modifier la valeur renvoyée par le premier.
Martin Bonner soutient Monica le
2
@MartinBonner ... mais uniquement dans le constructeur.
Dennis Kuypers
5
ou, comme toujours, à travers la réflexion (petite pinaillerie)
Marco Mp