Propriété automatisée avec getter uniquement, peut être définie, pourquoi?

96

J'ai créé une propriété automatisée:

public int Foo { get; } 

Ceci est uniquement un getter. Mais quand je construis un constructeur, je peux changer la valeur:

public MyClass(string name)
{
    Foo = 5;
}

Pourquoi est-ce possible, même s'il s'agit d'un accès exclusif?

Noam B.
la source
Il n'utilise pas réellement de setter (car il n'en a pas). Il définit directement le champ sous-jacent (qui nous est caché, c'est pourquoi vous devez utiliser le nom de la propriété)
Dennis_E
14
À quoi sert une propriété, si elle ne peut jamais être initialisée / définie? Yacoub Massad a parfaitement répondu
Vikhram

Réponses:

123

Il s'agit d'une nouvelle fonctionnalité C # 6, «Propriétés automatiques en lecture seule», également appelées «Initialiseurs de propriété automatique pour les propriétés en lecture seule», comme indiqué dans cet article du magazine MSDN «C #: The New and Improved C # 6.0» par Mark Michaelis et dans le projet de spécification de langage C # 6.0 .

Le setter du champ en lecture seule n'est accessible que dans le constructeur, dans tous les autres scénarios, le champ est toujours en lecture seule et se comporte comme avant.

Il s'agit d'une syntaxe pratique pour réduire la quantité de code à taper et pour supprimer le besoin de déclarer explicitement une variable de niveau de module privé pour contenir la valeur.

Cette fonctionnalité était considérée comme importante car, depuis l'introduction des propriétés auto-implémentées en C # 3, les propriétés mutables (celles avec un getter et un setter) étaient devenues plus rapides à écrire que les immuables (celles avec seulement un getter), ce qui signifie que les gens étaient être tenté d'utiliser des propriétés mutables pour éviter d'avoir à taper le code d'un champ de sauvegarde généralement requis pour les propriétés en lecture seule. Il y a plus de discussion sur les propriétés implémentées automatiquement dans la section appropriée du Guide de programmation Microsoft C # .

Ce billet de blog, '# 1,207 - C # 6.0 - Initialiseurs de propriétés automatiques pour les propriétés en lecture seule' par Sean Sexton a une bonne explication et un exemple comme suit:

Avant C # 6.0, si vous vouliez une propriété en lecture seule (immuable), vous utilisiez généralement un champ de sauvegarde en lecture seule initialisé dans le constructeur, comme indiqué ci-dessous.

public class Dog 
{
    public string Name { get; set; }

    // DogCreationTime is immutable
    private readonly DateTime creTime;
    public DateTime DogCreationTime 
    {
        get { return creTime; }
    }

    public Dog(string name)
    {
        Name = name;
        creTime = DateTime.Now;
    }
}

Dans C # 6.0, vous pouvez utiliser des propriétés implémentées automatiquement pour implémenter une propriété en lecture seule. Pour ce faire, utilisez un initialiseur de propriété automatique. Le résultat est beaucoup plus propre que l'exemple ci-dessus, où nous avons dû déclarer explicitement un champ de sauvegarde.

public class Dog
{
    public string Name { get; set; }

    // DogCreationTime is immutable
    public DateTime DogCreationTime { get; } = DateTime.Now;

    public Dog(string name)
    {
        Name = name;
    }
}

Plus de détails peuvent également être trouvés dans le repo dotnet Roslyn sur GitHub :

Les propriétés automatiques peuvent désormais être déclarées sans setter.

Le champ de sauvegarde d'une propriété automatique en lecture seule est implicitement déclaré comme en lecture seule (bien que cela ne soit important qu'à des fins de réflexion). Il peut être initialisé via un initialiseur sur la propriété comme dans l'exemple ci-dessus. En outre, une propriété en lecture seule peut être affectée dans le corps du constructeur du type de déclaration, ce qui entraîne l'affectation directe de la valeur au champ sous-jacent:

Il s'agit d'exprimer les types de manière plus concise, mais notez que cela supprime également une différence importante dans le langage entre les types mutables et immuables: les propriétés automatiques étaient un raccourci disponible uniquement si vous étiez prêt à rendre votre classe mutable, et donc la tentation de par défaut à cela était super. Maintenant, avec les propriétés automatiques uniquement en lecture, le terrain de jeu a été nivelé entre mutable et immuable.

et dans le projet de spécification du langage C # 6.0 (NB: la spécification du langage est définitive pour Microsoft, mais elle n'a pas encore été approuvée en tant que norme EMCA / ISO , d'où le `` projet ''):

Propriétés implémentées automatiquement

Une propriété implémentée automatiquement (ou auto-propriété en abrégé) est une propriété non abstraite non externe avec des corps d'accesseurs en point-virgule uniquement. Les propriétés automatiques doivent avoir un accesseur get et peuvent éventuellement avoir un accesseur set.

Lorsqu'une propriété est spécifiée en tant que propriété implémentée automatiquement, un champ de sauvegarde masqué est automatiquement disponible pour la propriété et les accesseurs sont implémentés pour lire et écrire dans ce champ de sauvegarde. Si la propriété automatique n'a pas d'accesseur défini, le champ de sauvegarde est considéré en lecture seule (champs en lecture seule). Tout comme un champ en lecture seule, une propriété automatique en lecture seule peut également être affectée dans le corps d'un constructeur de la classe englobante. Une telle affectation est directement affectée au champ de sauvegarde en lecture seule de la propriété.

Une propriété automatique peut éventuellement avoir un property_initializer, qui est appliqué directement au champ de sauvegarde en tant que variable_initializer (initialiseurs de variable).

tomRedox
la source
1
C'est une conception stupide. Il doit s'agir d'une erreur de compilation si elle est définie à un emplacement où la propriété est considérée en lecture seule.
Shiv
La bizarrerie pour moi est qu'il y a toujours une erreur du compilateur qui dit CS0200 C# Property or indexer cannot be assigned to -- it is read onlylors de l'utilisation d'une propriété régulière. Les "propriétés automatiques en lecture seule" sont-elles considérées en lecture seule ou non?
Kyle Delaney le
24

Il s'agit d' une nouvelle fonctionnalité en C # 6 qui vous permet de créer des propriétés en lecture seule et d'initialiser leurs valeurs à partir du constructeur (ou en ligne lorsque vous les déclarez).

Si vous essayez de modifier la valeur de cette propriété en dehors du constructeur, cela vous donnerait une erreur de compilation.

Il est en lecture seule dans le sens où une fois que vous initialisez sa valeur (en ligne ou à l'intérieur du constructeur), vous ne pouvez pas modifier sa valeur.

Yacoub Massad
la source
Alors, quelle est l'explication? Quelle est la définition d'un getter?
Noam B.
16

S'il n'était pas possible d'initialiser la propriété en lecture seule à partir du constructeur (ou d'un initialiseur de propriété automatique), alors cela serait inutile, car il retournerait toujours la valeur par défaut pour son type (0 pour les numériques, null pour les types de référence ). La même sémantique appliquée aux champs en lecture seule dans toutes les versions C #.

Pour définir une véritable propriété en lecture seule (qui ne peut pas être initialisée à partir du constructeur), vous devez spécifier ce qu'elle renvoie dans le cadre de la définition:

public int Foo { get { return 5; } }

Ou, plus concisément en C # 6:

public int Foo => 5;
Douglas
la source
Ce n'est pas tout à fait vrai, les propriétés en lecture seule sont très utiles pour encapsuler certaines conditions dans votre code. Vous pouvez écrire une instruction if et presque n'importe quel code pour évaluer d'autres propriétés ou conditions et renvoyer une valeur appropriée chaque fois que vous lisez la propriété
sebagomez
3
@sebagomez: Je ne suis pas sûr d'avoir compris votre point - n'est-ce pas ce que j'ai démontré dans mon exemple?
Douglas
5

"Propriétés implémentées automatiquement en lecture seule"

Tout d'abord, je tiens à préciser que la propriété comme

public string FirstName { get; }

Est appelé «propriétés implémentées automatiquement en lecture seule»

Pour vérifier cela, vous pouvez exécuter et vérifier le code ci-dessus avec Visual Studio. Si vous modifiez la version du langage de C # 6.0 à C # 5.0, le compilateur lèvera l'exception suivante. La fonctionnalité «Propriétés implémentées automatiquement en lecture seule» n'est pas disponible en C # 5. Veuillez utiliser la version de langage 6 ou supérieure.

pour changer la version du langage C #, visitez ici

J'en viens maintenant à votre deuxième question

«Ce n'est que du getter. Mais quand je construis un constructeur, je peux changer la valeur »

Microsoft introduit les «propriétés implémentées automatiquement en lecture seule» sur la logique de lecture seule. Comme nous le savons, le mot-clé «lecture seule» est disponible à partir de C # 1.0. nous utilisons le mot clé «readonly» comme modificateur sur un champ et ce champ peut être assigné de 2 façons soit au moment de la déclaration, soit dans un constructeur de la même classe.

De la même manière, la valeur des «propriétés implémentées automatiquement en lecture seule» peut être attribuée de 2 manières

Way1 (au moment de la déclaration):

public string FirstName { get; } = "Banketeshvar";

Way2 (dans un constructeur de la même classe)

Person()
{
 FirstName  = "Banketeshvar";
}

Propriété en lecture seule

Si vous recherchez une propriété en lecture seule, optez pour ceci

public string FullName => "Manish Sharma";

maintenant vous ne pouvez pas attribuer la valeur de la propriété «FullName» à partir du constructeur. Si vous essayez de le faire, les exceptions suivantes seront levées

"La propriété ou l'indexeur" Person.FullName "ne peut pas être attribué à - il est en lecture seule"

Banketeshvar Narayan
la source
2
notez que FullName => "foo bar" sera évalué CHAQUE FOIS.
juFo
4

La fonctionnalité de propriété automatique a été ajoutée au langage lors de la version C # 3.0. Il vous permet de définir une propriété sans aucun champ de sauvegarde, mais vous devez toujours utiliser le constructeur pour initialiser ces propriétés automatiques à une valeur autre que celle par défaut. C # 6.0 introduit une nouvelle fonctionnalité appelée initialiseur de propriété automatique qui vous permet d'initialiser ces propriétés sans constructeur comme ci-dessous:

Auparavant, un constructeur est requis si vous souhaitez créer des objets à l'aide d'une propriété automatique et initialiser une propriété automatique à une valeur non par défaut comme ci-dessous:

public class MyClass
{
    public int Foo { get; }

    public Foo(int foo)
    {
        Foo = foo;
    }
}

Désormais en C # 6.0, la possibilité d'utiliser un initialiseur avec la propriété automatique signifie qu'aucun code de constructeur explicite n'est requis.

public string Foo { get; } = "SomeString";

public List<string> Genres { get; } = new List<string> { "Comedy", "Drama" };

Vous pouvez trouver plus d'informations à ce sujet ici

Rahul Nikate
la source
1

Une variable déclarée readonlypeut être écrite dans un constructeur, mais dans des langages qui respectent l'attribut, ne peut pas être modifiée après le retour du constructeur. Ce qualificatif a été fourni en tant que fonctionnalité de langage car il est souvent nécessaire pour les champs dont les valeurs varient en fonction des paramètres du constructeur (ce qui signifie qu'ils ne peuvent pas être initialisés avant le démarrage du constructeur) mais n'auront pas à changer après le retour des constructeurs, mais c'était utilisable uniquement pour les variables exposées sous forme de champs. La sémantique des readonlychamps qualifiés aurait dans de nombreux cas été parfaite pour les membres publics, sauf qu'il est souvent préférable pour les classes d'exposer les membres - même immuables - comme des propriétés plutôt que des champs.

Tout comme les propriétés automatiques en lecture-écriture existent pour permettre aux classes d'exposer des propriétés mutables aussi facilement que les champs ordinaires, des propriétés automatiques en lecture seule existent pour permettre aux classes d'exposer des propriétés immuables aussi facilement que des readonlychamps qualifiés. Tout comme les readonlychamps qualifiés peuvent être écrits dans un constructeur, il en va de même pour les propriétés get-only.

supercat
la source