Auto-propriétés C # 3.0 - utiles ou pas? [fermé]


155

Remarque: Cela a été publié lorsque j'ai commencé C #. Avec les connaissances de 2014, je peux vraiment dire que les propriétés automatiques sont parmi les meilleures choses qui soient jamais arrivées au langage C #.

Je suis habitué à créer mes propriétés en C # en utilisant un champ privé et un champ public:

private string title;
public string Title
{
    get { return title;  }
    set { title = value;  }
}

Maintenant, avec .NET 3.0, nous avons des propriétés automatiques:

public string Title { get; set; }

Je sais qu'il s'agit plutôt de questions philosophiques / subjectives, mais y a-t-il une raison d'utiliser ces propriétés automatiques, sauf pour enregistrer cinq lignes de code pour chaque champ? Mon reproche personnel est que ces propriétés me cachent des choses, et je ne suis pas un grand fan de magie noire.

En fait, le champ privé caché n'apparaît même pas dans le débogueur, ce qui est OK étant donné que les fonctions get / set ne font rien. Mais quand je veux réellement implémenter une logique getter / setter, je dois quand même utiliser la paire privé / public.

Je vois l'avantage que j'économise beaucoup de code (une contre six lignes) sans perdre la possibilité de changer la logique getter / setter plus tard, mais là encore je peux déjà le faire en déclarant simplement un champ public "Public string Title" sans le besoin du {get; ensemble; }, ce qui permet même d'économiser plus de code.

Alors, qu'est-ce que je manque ici? Pourquoi quelqu'un voudrait-il réellement utiliser les propriétés automatiques?


86
"Mon reproche personnel est que ces propriétés me cachent des trucs, et je ne suis pas un grand fan de magie noire." Hein? Vous êtes conscient que le compilateur vous cache une tonne tout le temps, non? À moins que vous n'écriviez l'assembly (ou plus précisément, les 1 et 0 réels de votre code), TOUT ce que vous écrivez vous cache des choses.
Charles Boyung

Réponses:



62

Oui, cela enregistre simplement le code. C'est des kilomètres plus faciles à lire lorsque vous en avez plein. Ils sont plus rapides à écrire et plus faciles à entretenir. L'enregistrement du code est toujours un bon objectif.

Vous pouvez définir différentes étendues:

public string PropertyName { get; private set; }

Pour que la propriété ne puisse être modifiée qu'à l'intérieur de la classe. Ce n'est pas vraiment immuable car vous pouvez toujours accéder au setter privé par réflexion.

À partir de C # 6, vous pouvez également créer de vraies readonlypropriétés, c'est-à-dire des propriétés immuables qui ne peuvent pas être modifiées en dehors du constructeur:

public string PropertyName { get; }

public MyClass() { this.PropertyName = "whatever"; }

Au moment de la compilation, cela deviendra:

readonly string pName;
public string PropertyName { get { return this.pName; } }

public MyClass() { this.pName = "whatever"; }

Dans les classes immuables avec beaucoup de membres, cela économise beaucoup de code en excès.


"Donc vous ne perdez aucune fonctionnalité." comment les déboguer?
wal

2
@wal - qu'y a-t-il à déboguer? De ce point de vue, vous avez essentiellement affaire à des variables membres.
Keith

6
@wal - Vous pouvez mettre un point d'arrêt sur eux, tout comme vous pouvez accéder à une variable membre, vous ne pouvez tout simplement pas y entrer. Mais pourquoi le voudriez-vous? Ce que font réellement les propriétés automatiques est à la fois trivial et généré automatiquement, si vous avez des bogues, c'est un endroit où ils sont extrêmement improbables.
Keith

3
nous devrons peut-être sortir cela de Keith. :)
wal

1
Mais ok, supposons que vous ayez beaucoup d'appels setter à myObj.Title ... vous voulez voir où la valeur passe de "text" à null, c'est-à-dire un point d'arrêt conditionnel. comment y parvenir? vous ne pouvez même pas définir un point d'arrêt sur le passeur
wal

45

Les trois grands inconvénients de l'utilisation de champs au lieu de propriétés sont:

  1. Vous ne pouvez pas associer de données à un champ alors que vous le pouvez à une propriété
  2. Si vous commencez par utiliser un champ, vous ne pouvez plus (facilement) le changer en propriété
  3. Il existe des attributs que vous pouvez ajouter à une propriété que vous ne pouvez pas ajouter à un champ

7
"Si vous commencez par utiliser un champ, vous ne pouvez plus (facilement) le changer en propriété", désolé mais pourquoi?
Homam

6
@Homam Principalement, tout code consommateur qui utilise la réflexion sur vos champs serait interrompu, car ils devraient passer de FieldInfo à PropertyInfo.
WCWedin

8
@Homam De plus, changer un champ en propriété rompt la compatibilité binaire, obligeant tous les consommateurs du champ à se recompiler.
Odrade

1
Hormis les problèmes de recompilation et de réflexion, il est très facile d'encapsuler des champs à l'aide de Visual Studio: Ctrl-R + E vous permettra de transformer un champ en propriété avec les getters / setters appropriés. (ou cliquez avec le bouton droit sur le champ, re-factoriser, encapsuler le champ).
JoeBrockhaus

Les champs @Hommam sont des valeurs l (ce sont des variables) et les propriétés ne le sont pas. Les éléments qui auraient pu être compilés lorsqu'il s'agissait d'un champ peuvent ne pas l'être lorsqu'il s'agit d'une propriété.
Mark

29

Personnellement, j'aime les propriétés automobiles. Quel est le problème avec l'enregistrement des lignes de code? Si vous voulez faire des choses dans des getters ou des setters, il n'y a aucun problème pour les convertir en propriétés normales plus tard.

Comme vous l'avez dit, vous pouvez utiliser des champs, et si vous souhaitez leur ajouter une logique plus tard, vous les convertissez en propriétés. Mais cela pourrait poser des problèmes avec toute utilisation de la réflexion (et peut-être ailleurs?).

De plus, les propriétés vous permettent de définir différents niveaux d'accès pour le getter et le setter, ce que vous ne pouvez pas faire avec un champ.

Je suppose que c'est le même que le mot-clé var. Une question de préférence personnelle.


29

De Bjarne Stroustrup, créateur de C ++:

Je n'aime pas particulièrement les classes avec beaucoup de fonctions get et set. C'est souvent une indication que cela n'aurait pas dû être une classe en premier lieu. C'est juste une structure de données. Et s'il s'agit vraiment d'une structure de données, faites-en une structure de données.

Et tu sais quoi? Il a raison. Combien de fois encapsulez-vous simplement des champs privés dans un get et un set, sans rien faire dans le get / set, simplement parce que c'est la chose "orientée objet" à faire. C'est la solution de Microsoft au problème; ce sont essentiellement des champs publics auxquels vous pouvez vous lier.


2
Je pense vraiment que cela devrait avoir plus de points. Beaucoup trop de gens considèrent les propriétés automobiles comme un feu vert pour écrire des classes horriblement encapsulées (ou pas du tout encapsulées) qui ne sont guère plus qu'un domaine public glorifié. Bien sûr, c'est plus un problème avec la façon dont les gens utilisent l'outil plutôt qu'avec l'outil lui-même, mais je pense qu'il est important de le mentionner lors de la discussion des propriétés en général.
sara le

18

Une chose que personne ne semble avoir mentionnée est que les propriétés automatiques ne sont malheureusement pas utiles pour les objets immuables (généralement des structures immuables). Parce que pour cela, vous devriez vraiment faire:

private readonly string title;
public string Title
{
    get { return this.title; }
}

(où le champ est initialisé dans le constructeur via un paramètre passé, puis est en lecture seule.)

Cela présente donc des avantages par rapport à une propriété simple get/ private setautomatique.


Si vous avez une structure, la modification d'une propriété entraîne la création d'une nouvelle structure. Ce ne serait un problème que si vous vouliez un type de référence immuable en interne - je ne vois pas pourquoi vous en auriez besoin.
Keith

@Keith: Votre première phrase semble factuellement incorrecte.
Domenic

3
Cela n'aboutirait-il pas public string Title { get; private set; }exactement à la même chose? Vous seriez capable de le changer depuis l'intérieur de la classe alors bien sûr, mais si vous faites cela, vous avez d'autres problèmes ...: p
Svish

2
@Svish - par cet argument, le mot clé readonly en C # ne devrait jamais être utilisé car son utilisation signifierait que nous masquions ces "différents problèmes"
Zaid Masud

2
Je veux simplement dire que d'un point de vue extérieur à l'API, cela ne ferait pas beaucoup de différence. Et donc, les propriétés automatiques peuvent être utilisées si vous le souhaitez. La meilleure chose serait bien sûr si vous pouviez faire quelque chose commepublic string Title { get; private readonly set; }
Svish

12

Je crée toujours des propriétés au lieu de champs publics car vous pouvez utiliser des propriétés dans une définition d'interface, vous ne pouvez pas utiliser de champs publics dans une définition d'interface.


8

Les propriétés automatiques sont autant une magie noire que toute autre chose en C #. Une fois que vous y réfléchissez en termes de compilation en IL plutôt que d'être étendu à une propriété C # normale, c'est beaucoup moins de magie noire que beaucoup d'autres constructions de langage.


5

J'utilise les propriétés automatiques tout le temps. Avant C # 3, je ne pouvais pas être dérangé par toute la saisie et j'utilisais simplement des variables publiques à la place.

La seule chose qui me manque, c'est de pouvoir le faire:

public string Name = "DefaultName";

Vous devez déplacer les valeurs par défaut dans vos constructeurs avec des propriétés. fastidieux :-(


4
Avec les initialiseurs de propriété automatique de C # 6, vous pourrez bientôt le faire: public string Name { get; set; } = "DefaultName"; blogs.msdn.com/b/csharpfaq/archive/2014/11/20
Carlos Muñoz

5

Je pense que toute construction intuitive ET qui réduit les lignes de code est un gros plus.

Ces types de fonctionnalités sont ce qui rend des langages comme Ruby si puissants (cela et des fonctionnalités dynamiques, qui aident également à réduire l'excès de code).

Ruby a toujours eu ceci comme:

attr_accessor :my_property
attr_reader :my_getter
attr_writer :my_setter

2

Le seul problème que j'ai avec eux, c'est qu'ils ne vont pas assez loin. La même version du compilateur qui a ajouté des propriétés automatiques, ajouté des méthodes partielles. Pourquoi ils n'ont pas mis les deux ensemble me dépasse. Un simple «partiel On <PropertyName> Changed» aurait rendu ces choses vraiment très utiles.


Vous pouvez placer plusieurs méthodes partielles dans une autre méthode. Créer un modèle automatique pour eux serait déroutant.
Matthew Whited

2

C'est simple, c'est court et si vous voulez créer une implémentation réelle à l'intérieur du corps de la propriété quelque part sur la ligne, cela ne cassera pas l'interface externe de votre type.

Aussi simple que cela.


1

Une chose à noter ici est que, à ma connaissance, il ne s'agit que de sucre syntaxique à l'extrémité C # 3.0, ce qui signifie que l'IL généré par le compilateur est le même. Je suis d'accord pour éviter la magie noire, mais tout de même, moins de lignes pour la même chose est généralement une bonne chose.


1

À mon avis, vous devriez toujours utiliser les propriétés automatiques au lieu des champs publics. Cela dit, voici un compromis:

Commencez par un champ interne en utilisant la convention de dénomination que vous utiliseriez pour une propriété. La première fois que vous

  • besoin d'accéder au champ depuis l'extérieur de son assemblage, ou
  • besoin d'attacher une logique à un getter / setter

Faites ceci:

  1. renommer le champ
  2. le rendre privé
  3. ajouter une propriété publique

Votre code client n'aura pas besoin de changer.

Un jour, cependant, votre système grandira et vous le décomposerez en assemblages séparés et en plusieurs solutions. Lorsque cela se produit, tous les champs exposés reviendront vous hanter car, comme Jeff l'a mentionné, changer un champ public en propriété publique est un changement radical de l'API .


0

J'utilise CodeRush, c'est plus rapide que les propriétés automatiques.

Pour faire ça:

 private string title;
public string Title
{
    get { return title;  }
    set { title = value;  }
}

Nécessite huit frappes au total.


5
Si je maintiens CTRL et V enfoncés, je peux coller beaucoup, beaucoup de choses, / très rapidement /, mais cela ne le rend pas «meilleur». Comment cela répond-il à la question initiale?
JBRWilkinson

0

Eh bien, avec des extraits de code, une propriété automatique du même nom équivaudrait à sept frappes au total;)


0

@Domenic: Je ne comprends pas ... tu ne peux pas faire ça avec les propriétés automatiques?:

public string Title { get; }

ou

public string Title { get; private set; }

Est-ce ce à quoi vous parlez?


Vous pouvez (ce dernier; le premier ne compilera pas), mais alors le champ n'est pas immuable à l'intérieur de votre objet.
Domenic

Attention, seules les structures sont immuables lorsqu'elles sont marquées en lecture seule, les classes ne sont tout simplement pas assignables.
Guvante

0

Mon plus gros reproche avec les propriétés automatiques est qu'elles sont conçues pour gagner du temps, mais je trouve souvent que je dois les développer plus tard dans des propriétés à part entière.

Ce qui manque à VS2008, c'est un refactor Explode Auto-Property .

Le fait que nous ayons un refactor de champ encapsulé rend la façon dont je travaille plus rapide pour n'utiliser que des champs publics.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.