web-dev-qa-db-fra.com

Propriétés automatiques C # - Pourquoi dois-je écrire "get; set;"?

Si à la fois get et set sont obligatoires dans les propriétés automatiques C #, pourquoi dois-je prendre la peine de spécifier "get; set;" du tout?

44
52d6c6af

ERREUR: une propriété ou un indexeur ne peut pas être passé en tant que paramètre out ou ref

Si vous n'avez pas spécifié {get; set;} alors le compilateur ne saurait pas s'il s'agit d'un champ ou d'une propriété. Ceci est important car ils "semblent" identiques, le compilateur les traite différemment. par exemple. L'appel de "InitAnInt" sur la propriété déclenche une erreur.

class Test
{
    public int n;
    public int i { get; set; }
    public void InitAnInt(out int p)
    {
        p = 100;
    }
    public Test()
    {
        InitAnInt(out n); // This is OK
        InitAnInt(out i); // ERROR: A property or indexer may not be passed 
                          // as an out or ref parameter
    }
}

Vous ne devriez pas créer de champs/variables publics sur les classes, vous ne savez jamais quand vous voudrez le changer pour avoir des accesseurs get & set, et alors vous ne savez pas quel code vous allez casser, surtout si vous avez clients qui programment contre votre API.

Vous pouvez également avoir différents modificateurs d'accès pour le get & set, par ex. {avoir; private set;} rend le get public et le set privé à la classe déclarante.

52
Binary Worrier

Parce que vous voudrez peut-être une propriété en lecture seule:

public int Foo { get; private set; }

Ou propriété en écriture seule:

public int Foo { private get; set; }
64
Brian Genisio

Je pensais juste partager mes conclusions sur ce sujet.

Le codage d'une propriété comme celle-ci est un appel de raccourci .net 3.0 "propriété implémentée automatiquement".

public int MyProperty { get; set; }

Cela vous évite de taper. Le long chemin pour déclarer une propriété est comme ceci:

private int myProperty;
public int MyProperty 
{
  get { return myProperty; }
  set { myProperty = value; } 
}

Lorsque vous utilisez la "propriété auto-implémentée", le compilateur génère le code pour câbler le get et défini sur un "k_BackingField". Vous trouverez ci-dessous le code désassemblé utilisant Reflector.

public int MyProperty
{
    [CompilerGenerated]
    get
    {
        return this.<MyProperty>k__BackingField;
    }
    [CompilerGenerated]
    set
    {
        this.<MyProperty>k__BackingField = value;
    }
}

code C # démonté d'IL

Câble également une méthode pour le setter et le getter.

[CompilerGenerated]
public void set_MyProperty(int value)
{
    this.<MyProperty>k__BackingField = value;
}
[CompilerGenerated]
public int get_MyProperty()
{
    return this.<MyProperty>k__BackingField;
}

code C # démonté d'IL

Lorsque vous déclarez une propriété en lecture seule implémentée automatiquement, en définissant le setter sur private:

 public int MyProperty { get; private set; }

Tout le compilateur marque le "set" comme privé. Les méthodes setter et getter disent la même chose.

public int MyProperty
{
    [CompilerGenerated]
    get
    {
        return this.<MyProperty>k__BackingField;
    }
    private [CompilerGenerated]
    set
    {
        this.<MyProperty>k__BackingField = value;
    }
}

code C # démonté d'IL

Je ne sais donc pas pourquoi le cadre requiert à la fois le get; Et mettre; sur une propriété implémentée automatiquement. Ils n'auraient tout simplement pas pu écrire la méthode set et setter si elle n'était pas fournie. Mais il peut y avoir un problème au niveau du compilateur qui rend cela difficile, je ne sais pas.

Si vous regardez la longue façon de déclarer une propriété en lecture seule:

public int myProperty = 0;
public int MyProperty
{
    get { return myProperty; }
}  

Et puis regardez le code démonté. Le passeur n'est pas là du tout.

public int Test2
{
    get
    {
        return this._test;
    }
}

public int get_Test2()
{
    return this._test;
}

code C # démonté d'IL

17
Ron Todosichuk

Parce que vous avez besoin d'un moyen de le distinguer des champs simples.

Il est également utile d'avoir différents modificateurs d'accès, par exemple.

public int MyProperty { get; private set; }
16
Cristian Libardo

Le compilateur doit savoir si vous voulez qu'il génère un getter et/ou un setter, ou peut-être déclarez un champ.

4
Kris

Eh bien, évidemment, vous avez besoin d'un moyen de lever l'ambiguïté entre les champs et les propriétés. Mais les mots clés requis sont-ils vraiment nécessaires? Par exemple, il est clair que ces deux déclarations sont différentes:

public int Foo;
public int Bar { }

Ça pourrait marcher. C'est-à-dire que c'est une syntaxe qu'un compilateur pourrait éventuellement comprendre.

Mais alors vous arrivez à une situation où un bloc vide a une signification sémantique. Cela semble précaire.

2
Robert Rossney

Si la propriété n'avait pas d'accesseurs, comment le compilateur la séparerait-il d'un champ? Et qu'est-ce qui le séparerait d'un champ?

2
Rune Grimstad

Puisque personne ne l'a mentionné ... vous pouvez rendre la propriété automatique virtuelle et la remplacer:

public virtual int Property { get; set; }

S'il n'y avait pas de get/set, comment serait-il remplacé? Notez que vous êtes autorisé à remplacer le getter et non le setter :

public override int Property { get { return int.MinValue; } }
2
Zaid Masud

De plus, car depuis C # 6.0 (dans Visual Studio 2015, au moment de cette réponse disponible dans la version Ultimate Preview), vous pouvez implémenter une véritable propriété en lecture seule:

public string Name { get; }
public string Name { get; } = "This won't change even internally";

... par opposition à une solution de contournement actuellement imparfaite avec une paire getter public/setter privé:

public string Name { get; private set; }

public Constructor() { Name="As initialised"; }
public void Method() { Name="This might be changed internally. By mistake. Or not."; }

Exemple de ce qui précède ci-dessous (compilé et exécutable en ligne ici ).

using System;

public class Propertier {
    public string ReadOnlyPlease { get; private set; }

    public Propertier()  { ReadOnlyPlease="As initialised"; }
    public void Method() { ReadOnlyPlease="This might be changed internally"; }
    public override string ToString() { return String.Format("[{0}]",ReadOnlyPlease); }
}

public class Program {
    static void Main() {
        Propertier p=new Propertier();
        Console.WriteLine(p);

//      p.ReadOnlyPlease="Changing externally!";
//      Console.WriteLine(p);

        // error CS0272: The property or indexer `Propertier.ReadOnlyPlease' cannot be used in this context because the set accessor is inaccessible
        // That's good and intended.

        // But...
        p.Method();
        Console.WriteLine(p);
    }
}

Autres nouvelles savoureuses sur C # 6.0 disponibles en tant que vidéo de prévisualisation officielle ici .

2
Robert Kopeć