Différence entre la propriété et le champ dans C # 3.0+

140

Je me rends compte qu'il semble être un double de Quelle est la différence entre un champ et une propriété en C #? mais ma question a une légère différence (de mon point de vue):

Une fois que je sais que

  • Je n'utiliserai pas ma classe avec des "techniques qui ne fonctionnent que sur les propriétés" et
  • Je n'utiliserai pas de code de validation dans le getter / setter.

Y a-t-il une différence (à l'exception du style / développement futur), comme un type de contrôle dans la définition de la propriété?

Y a-t-il une différence supplémentaire entre:

public string MyString { get; set; }

et

public string myString;

(Je suis conscient que la première version nécessite C # 3.0 ou supérieur et que le compilateur crée les champs privés.)

p4bl0
la source

Réponses:

117

Encapsulation.

Dans le second cas, vous venez de définir une variable, dans le premier, il y a un getter / setter autour de la variable. Donc, si vous décidez de valider la variable à une date ultérieure, ce sera beaucoup plus facile.

De plus, ils apparaissent différemment dans Intellisense :)

Edit: Question mise à jour pour les OP - si vous voulez ignorer les autres suggestions ici, l'autre raison est que ce n'est tout simplement pas une bonne conception OO. Et si vous n'avez pas une très bonne raison de le faire, choisissez toujours une propriété plutôt qu'une variable / un champ public.

Mark Ingram
la source
9
Pourquoi cela sera-t-il plus facile? Qu'est-ce qui m'empêche de transformer un champ en propriété et d'ajouter un champ de sauvegarde privé? Comment cela affecte-t-il le code d'appel?
Serge Wautier
30
@Serge - Cela affecte le code déjà compilé. Par exemple, si vous développez une bibliothèque utilisée par plusieurs applications, la modification d'un champ en propriété de cette bibliothèque nécessiterait une recompilation de chaque application. S'il s'agissait d'une propriété, vous pourriez mettre à jour la propriété sans souci.
Dustin Campbell
Je suis totalement d'accord avec vous, j'utilise toujours des propriétés. J'étais juste curieux d'une éventuelle différence
p4bl0
24
Si la consommation de code est toujours recompilée en même temps que la classe affectée (donc tout ce qui est privé ou interne sans éléments internes visibles est 100% sûr), alors en faire un champ est parfaitement OK
ShuggyCoUk
1
wow Shuggy votre commentaire est exactement la réponse que je recherchais!
p4bl0
160

Les champs et les propriétés se ressemblent, mais ils ne le sont pas. Les propriétés sont des méthodes et, en tant que telles, certaines choses ne sont pas prises en charge pour les propriétés, et certaines choses peuvent se produire avec les propriétés mais jamais dans le cas des champs.

Voici une liste de différences:

  • Les champs peuvent être utilisés comme entrée d' out/refarguments. Les propriétés ne peuvent pas.
  • Un champ donnera toujours le même résultat lorsqu'il est appelé plusieurs fois (si nous omettons les problèmes avec plusieurs threads). Une propriété telle que DateTime.Nown'est pas toujours égale à elle-même.
  • Les propriétés peuvent lever des exceptions - les champs ne le feront jamais.
  • Les propriétés peuvent avoir des effets secondaires ou prendre beaucoup de temps à s'exécuter. Les champs n'ont pas d'effets secondaires et seront toujours aussi rapides que possible pour le type donné.
  • Les propriétés prennent en charge une accessibilité différente pour les getters / setters - les champs ne le font pas (mais les champs peuvent être créés readonly)
  • Lors de l'utilisation de la réflexion, les propriétés et les champs sont traités comme différents MemberTypes, ils sont donc situés différemment ( GetFieldsvs GetPropertiespar exemple)
  • Le compilateur JIT peut traiter l'accès aux propriétés très différemment par rapport à l'accès aux champs. Il peut cependant se compiler en un code natif identique, mais la différence est là.
Brian Rasmussen
la source
11
Notez cependant que plusieurs de ces points ne devraient pas être des différences si de bonnes pratiques sont employées. Autrement dit, les propriétés ne devraient jamais avoir d'effets secondaires et ne devraient pas prendre beaucoup de temps à s'exécuter.
Noldorin
15
@Noldorin: Je suis d'accord, mais le mot-clé devrait malheureusement être ici. Avec les champs, ce comportement est garanti. Je ne dis pas que vous devriez utiliser des champs, mais il est important d'être conscient des différences sémantiques.
Brian Rasmussen
4
Ouais, assez bien. Les programmeurs débutants n'ont souvent aucune idée de ces choses, malheureusement ...
Noldorin
2
De plus, les champs peuvent avoir un initialiseur de champ tandis que les propriétés doivent être initialisées dans un constructeur.
Dio F
3
Je pense que cette réponse est plus grande que la réponse acceptée. Je commence à penser que la manière «acceptable» de toujours préférer les propriétés aux champs est une mauvaise pensée. Si vous ne devez traiter que des données, utilisez un champ. Si vous devez appliquer des fonctionnalités aux données, utilisez une méthode. Puisque les propriétés peuvent avoir des effets secondaires que vous ne connaissez pas (surtout si vous n'avez pas conçu la bibliothèque et avez peu de documentation), elles me semblent contre-intuitives dans la plupart des cas.
David Peterson le
41

Quelques différences rapides et évidentes

  1. Une propriété peut avoir des mots-clés d'accesseur.

    public string MyString { get; private set; }
  2. Une propriété peut être remplacée dans les descendants.

    public virtual string MyString { get; protected set; }
Dustin Campbell
la source
1
mmh .. nr 2 est intéressant .. je n'y ai pas pensé
p4bl0
14

La différence fondamentale est qu'un champ est une position en mémoire où les données du type spécifié sont stockées. Une propriété représente une ou deux unités de code qui sont exécutées pour récupérer ou définir une valeur du type spécifié. L'utilisation de ces méthodes d'accès est masquée syntaxiquement en utilisant un membre qui semble se comporter comme un champ (en ce sens qu'il peut apparaître de chaque côté d'une opération d'affectation).

AnthonyWJones
la source
11

Les accesseurs sont plus que des champs. D'autres ont déjà signalé plusieurs différences importantes, et je vais en ajouter une de plus.

Les propriétés participent aux classes d'interface. Par exemple:

interface IPerson
{
    string FirstName { get; set; }
    string LastName { get; set; }
}

Cette interface peut être satisfaite de plusieurs manières. Par exemple:

class Person: IPerson
{
    private string _name;
    public string FirstName
    {
        get
        {
            return _name ?? string.Empty;
        }
        set
        {
            if (value == null)
                throw new System.ArgumentNullException("value");
            _name = value;
        }
    }
    ...
}

Dans cette implémentation, nous protégeons à la fois la Personclasse contre un état non valide, ainsi que l'appelant contre la suppression de null de la propriété non attribuée.

Mais nous pourrions pousser le design encore plus loin. Par exemple, l'interface peut ne pas traiter le setter. Il est tout à fait légitime de dire que les consommateurs d' IPersoninterface ne sont intéressés qu'à obtenir la propriété, pas à la définir:

interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}

L'implémentation précédente de la Personclasse satisfait cette interface. Le fait qu'il laisse l'appelant définir également les propriétés n'a pas de sens du point de vue des consommateurs (qui consomment IPerson). Une fonctionnalité supplémentaire de l'implémentation concrète est prise en compte par, par exemple, le constructeur:

class PersonBuilder: IPersonBuilder
{
    IPerson BuildPerson(IContext context)
    {

        Person person = new Person();

        person.FirstName = context.GetFirstName();
        person.LastName = context.GetLastName();

        return person;

    }
}

...

void Consumer(IPersonBuilder builder, IContext context)
{
    IPerson person = builder.BuildPerson(context);
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

Dans ce code, le consommateur ne connaît pas les poseurs de propriété - ce n'est pas son affaire de le savoir. Le consommateur n'a besoin que de getters, et il obtient des getters de l'interface, c'est-à-dire du contrat.

Une autre implémentation complètement valide de IPersonserait une classe de personne immuable et une fabrique de personnes correspondante:

class Person: IPerson
{
    public Person(string firstName, string lastName)
    {

        if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
            throw new System.ArgumentException();

        this.FirstName = firstName;
        this.LastName = lastName;

    }

    public string FirstName { get; private set; }

    public string LastName { get; private set; }

}

...

class PersonFactory: IPersonFactory
{
    public IPerson CreatePerson(string firstName, string lastName)
    {
        return new Person(firstName, lastName);
    }
}
...
void Consumer(IPersonFactory factory)
{
    IPerson person = factory.CreatePerson("John", "Doe");
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

Dans cet exemple de code, le consommateur n'a à nouveau aucune connaissance du remplissage des propriétés. Le consommateur ne s'occupe que des getters et de l'implémentation concrète (et la logique métier derrière elle, comme tester si le nom est vide) est laissée aux classes spécialisées - constructeurs et usines. Toutes ces opérations sont absolument impossibles avec les champs.

Zoran Horvat
la source
7

Le premier:

public string MyString {get; set; }

est une propriété; le deuxième (public string MyString ) désigne un champ.

La différence est que certaines techniques (liaison de données ASP.NET pour les instances) ne fonctionnent que sur les propriétés et non sur les champs. Il en va de même pour la sérialisation XML: seules les propriétés sont sérialisées, les champs ne sont pas sérialisés.

Frederik Gheysels
la source
8
Faux. La sérialisation XML sérialise les champs publics.
Serge Wautier
2
Peut être. Mais lorsque vous créez une source de données objet à partir d'une classe, vous n'utilisez que les propriétés, pas les champs. (Sauf si j'ai fait quelque chose de mal: P)
Svish
Bon c'est à DRY;) mais j'écris encore une fois, j'aime le rôle fort de la propriété en langage C #. Est bien mieux implémenté qu'en Java (par conséquent depuis le début) Beaucoup, peut-être toutes les solutions .net ne fonctionnent que sur les propriétés. WPF, ASPX et plus encore.
Jacek Cz
3

Les propriétés et les champs peuvent, dans de nombreux cas, sembler similaires, mais ils ne le sont pas. Il existe des limitations aux propriétés qui n'existent pas pour les champs, et vice versa.

Comme d'autres l'ont mentionné. Vous pouvez rendre une propriété en lecture seule ou en écriture seule en rendant son accesseur privé. Vous ne pouvez pas faire cela avec un champ. Les propriétés peuvent également être virtuelles, contrairement aux champs.

Considérez les propriétés comme du sucre syntaxique pour les fonctions getXXX () / setXXX (). C'est ainsi qu'ils sont mis en œuvre dans les coulisses.

Erik Funkenbusch
la source
1

Il existe une autre différence importante entre les champs et les propriétés.

Lorsque vous utilisez WPF, vous ne pouvez vous lier qu'à des propriétés publiques. La liaison à un champ public ne fonctionnera pas . Cela est vrai même si vous ne l'implémentez pas INotifyPropertyChanged(même si vous devriez toujours le faire).

BradleyDotNET
la source
Bon c'est à DRY;) mais j'écris encore une fois, j'aime le rôle fort de la propriété en langage C #. Est bien mieux implémenté qu'en Java (par conséquent depuis le début) Beaucoup, peut-être toutes les solutions .net ne fonctionnent que sur les propriétés. WPF, ASPX et plus encore.
Jacek Cz
1

Entre autres réponses et exemples, je pense que cet exemple est utile dans certaines situations.

Par exemple, disons que vous avez un suivant comme:OnChange property

public Action OnChange { get; set; }

Si vous souhaitez utiliser des délégués, vous devez le modifier OnChangepour qu'il fieldressemble à ceci:

public event Action OnChange = delegate {};

Dans une telle situation, nous protégeons notre champ contre tout accès ou modification indésirable.

maytham-ɯɐɥʇʎɐɯ
la source
0

Vous devez toujours utiliser des propriétés au lieu de champs pour tous les champs publics.Cela garantit que votre bibliothèque a la capacité d'implémenter l'encapsulation pour n'importe quel champ si nécessaire à l'avenir sans casser les codes existants.Si vous remplacez les champs par des propriétés dans les bibliothèques existantes, alors tous les les modules dépendants utilisant votre bibliothèque doivent également être reconstruits.

user1849310
la source
«toujours» est un mot difficile à comprendre. En C # (mieux qu'en Java), la propriété a une position forte, est (probablement sans exception) la principale / méthode de "liaison" dans ASP, WPF et autres. Mais néanmoins, je peux imaginer un design avec un champ, aucune propriété d'être n'a de sens (parfois)
Jacek Cz