web-dev-qa-db-fra.com

Quel est le meilleur entre un modificateur en lecture seule et un setter privé?

J'ai travaillé sur la création d'une classe et soudain, une pensée m'est venue à l'esprit quelle est la différence entre les deux codes:

public readonly string ProductLocation;

ET

public string ProductLocation
{
     get;
     private set;
}

Pouvez-vous me donner une idée du meilleur moment pour utiliser ce qui suit. Merci.

61
Allan Chua

Le premier est un champ en lecture seule, tandis que le second est compilé comme une paire de méthodes (et toutes les lectures de la propriété ProductLocation sont compilées en appels à la méthode get correspondante et écrit est compilé en appels à la méthode set; en interne, ces méthodes liront depuis/écrire dans un champ interne, généré automatiquement et non en lecture seule). Je dirais que la différence la plus importante est la sécurité des threads ! (comment? lisez la suite!)

L'utilisation de base de la classe aura la même apparence exactement: le code des autres classes ne pourra lire que la valeur, pas la changer. De plus, le code pour lire la valeur sera exactement le même (par exemple, print(myInstace.ProductLocation); ici, vous ne pouvez pas dire comment il a été déclaré, cool, hein?)

La première différence, la plus triviale, est que la propriété avec setter privé permet aux instances de la même classe de modifier la valeur, alors que dans le cas de la propriété en lecture seule, même l'objet lui-même ne pourra pas changer la valeur.

Maintenant, pour la sécurité des threads. L'attribut readonly sur le terrain changera sa sémantique de visibilité de la mémoire lorsque vous travaillez avec plusieurs threads (tout comme les champs final de Java).

Un champ readonly ne peut être affecté qu'à at declaration ou dans le constructeur. La valeur affectée à un champ readonly ne peut pas être modifiée (du moins pas de la manière normale) et il est garanti que chaque thread sera voir la valeur correctement initialisée après le retour du constructeur . Par conséquent, un champ readonly est intrinsèquement thread-safe.

Pour obtenir la même sécurité de thread avec la propriété, vous devez ajouter une synchronisation sur votre code, qui est sujet aux erreurs. Cela peut entraîner des blocages, des courses de données ou des performances réduites, selon le cas, et surtout si vous n'êtes pas expérimenté.

Donc, si la valeur représente quelque chose qui - sémantiquement ne peut pas être changé après la construction de l'objet, vous ne devez pas déclarer un setter privé (cela impliquerait que l'objet pourrait le changer). Optez pour le champ en lecture seule (et peut-être le déclarer privé et déclarer une propriété publique avec seulement un getter accédant au champ! C'est en fait la forme préférée, car il n'est pas bon d'exposer les champs, il est préférable d'exposer uniquement les méthodes - il sont de nombreuses raisons expliquant pourquoi dans cette réponse )

71
Bruno Reis

Avec C # 6. initialiseur de propriété automatique , il y a moins de méthode standard

private readonly string productLocation; 
public string ProductLocation { get { return productLocation; } } 

Lequel est

public string ProductLocation { get; } 

C'est en lecture seule. Uniquement initialisé à partir du constructeur ou en ligne. Il ne peut pas être modifié après l'initialisation. (Immuable de partout)

Cependant, si vous utilisez un ensemble privé;

public string ProductLocation { get; private set } 

C'est en lecture seule de l'extérieur. Mais peut être initialisé à tout moment et n'importe où dans la classe elle-même. Et peut être édité dans son cycle de vie par la classe elle-même. (Mutable de la classe, immuable de l'extérieur)

23
stratovarius

Généralement, il n'est pas recommandé dans .NET d'exposer publiquement les champs membres, ceux-ci doivent être encapsulés par une propriété. Supposons donc que vous pourriez avoir

private readonly string productLocation; 
public string ProductLocation { get { return productLocation; } } 

contre

public string ProductLocation { get; private set; }

Dans cette configuration, et en ignorant ce que l'on pourrait accomplir via la réflexion, la sémantique est que dans le premier cas, la variable productLocation ne peut être initialisée qu'en place et dans le constructeur de classe. Les autres membres de la classe ne peuvent pas modifier la valeur. Les consommateurs externes n'ont pas la possibilité de définir la valeur.

Dans la deuxième version, les consommateurs externes n'ont toujours pas accès à la définition de la valeur. Cependant, la classe elle-même peut modifier la valeur à tout moment. Si tout ce que vous avez est un DTO (c'est-à-dire une classe qui transporte uniquement des données, il n'a pas de logique exprimée via des méthodes), alors ce n'est pas si différent de la version readonly. Cependant, pour les classes avec des méthodes, ces méthodes peuvent modifier la valeur derrière ProductLocation.

Si vous souhaitez appliquer le concept d'un champ immuable post-construction, utilisez readonly. Mais pour un DTO, je pourrais opter pour le private set; option, principalement parce que c'est moins de code passe-partout.

18
Anthony Pegram

Le premier (en utilisant readonly) signifiera que l'objet ne peut même pas modifier la valeur de son propre champ, une fois que l'objet a été instancié et que d'autres ne peuvent jamais le modifier.

Le second (en utilisant private set) signifie que l'objet peut modifier la valeur de son champ après qu'il a été instancié, mais d'autres ne peuvent jamais le modifier.

J'utiliserais le premier pour quelque chose que vous savez ne changera pas, et j'utiliserais le dernier pour quelque chose où la valeur peut changer, mais vous ne voulez pas que les autres la changent.

8
Jon Newmuis

Le premier est un champ dont la valeur peut être définie niquement à l'instanciation.

Le second est un propriété dont la valeur peut être définie à à tout moment (mais uniquement par son objet conteneur).


Correction: La propriété peut être définie à tout moment par n'importe quelle instance de la même classe (et pas seulement par son objet conteneur).

4
Kirk Broadhurst