Je suis actuellement en classe C # et j'essaie de trouver la meilleure façon de faire les choses. Je viens de Java et je ne connais donc que les meilleures pratiques Java. Je suis un novice en C #!
En Java, si j'ai une propriété privée, je le fais;
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
En C #, je vois qu'il y a plusieurs façons de faire cela.
Je peux le faire comme Java:
private string name;
public void setName(string name) {
this.name = name;
}
public string getName() {
return this.name;
}
Ou je peux le faire de cette façon:
private string name;
public string Name {
get { return name; }
set { name = value; }
}
Ou:
public string Name { get; set; }
Lequel devrais-je utiliser et quelles sont les mises en garde ou les subtilités inhérentes à chaque approche? Lors de la création de classes, je suis les meilleures pratiques générales que je connais de Java (en particulier la lecture de Effective Java). Ainsi, par exemple, je privilégie l’immutabilité (ne fournir des setters que lorsque cela est nécessaire). Je suis simplement curieux de voir comment ces pratiques s’intègrent dans les différentes manières de fournir des setters et des getters en C #; Pour résumer, comment pourrais-je traduire les meilleures pratiques du monde Java en C #?
MODIFIER
Je publiais ceci comme commentaire à la réponse de Jon Skeet, mais ensuite cela a été long:
Qu'en est-il d'une propriété non-triviale (c'est-à-dire avec un traitement et une validation importants peut-être)? Pourrais-je quand même l'exposer via une propriété publique mais avec la logique encapsulée dans get
et set
? Pourquoi devrais-je/devrais-je faire cela plutôt que d'avoir des méthodes de définition et d'acquisition dédiées (avec une logique de traitement et de validation associée).
Pré-C # 6
Je voudrais utiliser le dernier d'entre eux, pour une propriété triviale. Notez que j'appellerais cela une propriété publique, car les accesseurs et les setters sont publics.
L'immuabilité est un peu pénible avec les propriétés implémentées automatiquement - vous ne pouvez pas écrire une propriété auto qui n'a qu'un getter; le plus proche, vous pouvez venir est:
public string Foo { get; private set; }
ce qui n’est pas vraiment immuable ... mais immuable en dehors de votre classe. Vous pouvez donc utiliser une propriété en lecture seule real:
private readonly string foo;
public string Foo { get { return foo; } }
Vous ne voulez certainement pas écrire getName()
et setName()
. Dans les cas {certains} _, il est logique d'écrire des méthodes Get/Set plutôt que d'utiliser des propriétés, en particulier si elles peuvent coûter cher et que vous souhaitez insister sur ce point. Cependant, vous voudriez suivre la convention de nommage .NET de PascalCase pour les méthodes et vous ne voudriez pas qu'une propriété triviale comme celle-ci soit implémentée avec des méthodes normales - une propriété est beaucoup plus idiomatique ici.
C # 6
Hourra, nous avons enfin les propriétés implémentées automatiquement en lecture seule:
// This can only be assigned to within the constructor
public string Foo { get; }
De même, pour les propriétés en lecture seule pour lesquelles do a besoin de travailler, vous pouvez utiliser les propriétés associées aux membres:
public double Area => height * width;
Si tout ce dont vous avez besoin est une variable pour stocker des données:
public string Name { get; set; }
Vous voulez le faire apparaître en lecture seule?
public string Name { get; private set; }
Ou même mieux ...
private readonly string _name;
...
public string Name { get { return _name; } }
Vous souhaitez vérifier certaines valeurs avant d’attribuer la propriété?
public string Name
{
get { return m_name; }
set
{
if (value == null)
throw new ArgumentNullException("value");
m_name = value;
}
}
En général, les méthodes GetXyz () et SetXyz () ne sont utilisées que dans certains cas, et il vous suffit d'utiliser votre instinct quand cela vous convient. En général, je dirais que je m'attends à ce que la plupart des propriétés get/set ne contiennent pas beaucoup de logique et aient très peu d'effets secondaires inattendus, voire aucun. Si la lecture d'une valeur de propriété nécessite d'appeler un service ou de demander à un utilisateur de générer l'objet que je demande, je l'envelopperais dans une méthode et l'appellerais comme suit: BuildXyz()
, plutôt que GetXyz()
.
Utilisez les propriétés en C #, pas les méthodes get/set. Ils sont là pour votre commodité et c’est idiomatique.
En ce qui concerne vos deux exemples C #, l’un est simplement un sucre syntaxique pour l’autre. Utilisez la propriété auto si vous n'avez besoin que d'un simple wrapper autour d'une variable d'instance. Utilisez la version complète lorsque vous devez ajouter une logique dans le getter et/ou le setter.
En C #, privilégiez les propriétés permettant d’exposer des champs privés pour get et/ou set. Le formulaire que vous mentionnez est une propriété automatique dans laquelle get et set génèrent automatiquement un champ de pivot caché pour vous.
Je privilégie les propriétés auto lorsque cela est possible, mais vous ne devriez jamais faire une paire méthode/get en C #.
public string Name { get; set; }
Ceci est simplement une propriété implémentée automatiquement , et est techniquement identique à une propriété normale. Un champ de sauvegarde sera créé lors de la compilation.
Toutes les propriétés sont finalement converties en fonctions, de sorte que l’implémentation réellement compilée est la même que celle utilisée en Java.
Utilisez des propriétés implémentées automatiquement lorsque vous n'avez pas à effectuer d'opérations spécifiques sur le champ de sauvegarde. Utilisez une propriété ordinaire autrement. Utilisez les fonctions get et set lorsque l'opération a des effets secondaires ou est coûteuse en calculs, utilisez les propriétés autrement.
Permettez-moi d’abord d’expliquer ce que vous avez écrit:
// private member -- not a property
private string name;
/// public method -- not a property
public void setName(string name) {
this.name = name;
}
/// public method -- not a property
public string getName() {
return this.name;
}
// yes it is property structure before .Net 3.0
private string name;
public string Name {
get { return name; }
set { name = value; }
}
De nos jours, cette structure est également utilisée, mais elle convient mieux si vous souhaitez apporter des fonctionnalités supplémentaires. Par exemple, lorsqu'une valeur est définie, vous pouvez l'analyser pour la mettre en majuscule et la sauvegarder dans un membre privé pour une utilisation interne.
Avec le framework .net 3.0
// this style is introduced, which is more common, and suppose to be best
public string Name { get; set; }
//You can more customize it
public string Name
{
get;
private set; // means value could be set internally, and accessed through out
}
Je vous souhaite une meilleure chance en C #
Quelle que soit la méthode choisie en C #, le résultat final est identique. Vous obtiendrez une variable backinng avec des méthodes getter et setter distinctes. En utilisant les propriétés, vous suivez les meilleures pratiques et vous devez donc savoir comment vous voulez en parler.
Personnellement, je choisirais les propriétés automatiques, la dernière version: public string Name { get; set; }
, car elles occupent le moins d'espace possible. Et vous pouvez toujours les développer ultérieurement si vous avez besoin d’ajouter quelque chose comme la validation.
Dans la mesure du possible, je préfère public string Name { get; set; }
car il est concis et facile à lire. Cependant, il peut y avoir des moments où celui-ci est nécessaire
private string name;
public string Name {
get { return name; }
set { name = value; }
}
En C #, la méthode préférée consiste à utiliser les propriétés plutôt que les méthodes getX()
et setX()
. Notez également que C # ne nécessite pas que les propriétés aient à la fois un get et un ensemble: vous pouvez avoir des propriétés get-only et set-only.
public boolean MyProperty
{
get { return something; }
}
public boolean MyProperty
{
set { this.something = value; }
}
Comme mentionné, toutes ces approches aboutissent au même résultat. Le plus important est que vous choisissiez une convention et que vous vous en teniez à elle. Je préfère utiliser les deux derniers exemples de propriétés.
comme la plupart des réponses ici, utilisez les propriétés automatiques. Intuitif, moins de lignes de code et c'est plus propre. Si vous devez sérialiser votre classe, marquez l'attribut de classe [Serializable]
/avec [DataConract]
. Et si vous utilisez [DataContract]
, marquez le membre avec
[DataMember(Name="aMoreFriendlyName")]
public string Name { get; set; }
Le passeur privé ou public dépend de votre préférence.
Notez également que les propriétés automatiques nécessitent à la fois des accesseurs (geters) et des setters (publics ou privés).
/*this is invalid*/
public string Name
{
get;
/* setter omitted to prove the point*/
}
Sinon, si vous voulez seulement obtenir/définir, créez vous-même un champ de sauvegarde
Lequel devrais-je utiliser et quelles sont les mises en garde ou les subtilités inhérentes à chaque approche?
En ce qui concerne les propriétés, il y a une mise en garde qui n'a pas encore été mentionnée: Avec les propriétés, vous ne pouvez pas paramétrer vos getters ou setters.
Par exemple, imaginons que vous souhaitiez récupérer un élément de liste et que vous souhaitiez également appliquer un filtre en même temps. Avec une méthode get, vous pouvez écrire quelque chose comme:
obj.getItems(filter);
En revanche, avec une propriété, vous êtes obligé de retourner tous les éléments
obj.items
puis appliquez le filtre à l'étape suivante ou vous devez ajouter des propriétés dédiées qui exposent les éléments filtrés par différents critères, ce qui alourdira bientôt votre API:
obj.itemsFilteredByX
obj.itemsFilteredByY
Ce qui peut parfois être une nuisance est lorsque vous avez commencé avec une propriété, par exemple. obj.items
et a découvert plus tard que la paramétrisation de getter ou de setter était nécessaire ou faciliterait les choses pour l'utilisateur de l'API de classe. Vous devez maintenant réécrire votre API et modifier tous les emplacements de votre code qui accèdent à cette propriété ou trouver une solution alternative. En revanche, avec une méthode get, par exemple obj.getItems()
, vous pouvez simplement étendre la signature de votre méthode pour accepter un objet "configuration" facultatif, par ex. obj.getItems(options)
sans avoir à réécrire tous les endroits qui appellent votre méthode.
Cela dit, les propriétés (auto-implémentées) en C # sont toujours des raccourcis très utiles (pour les diverses raisons mentionnées ici) car la paramétrisation n’est peut-être pas nécessaire, mais cette mise en garde tient.