2017-09-23 5 views
2

Comment vous pouvez définir une auto-propriété get-only à partir d'un constructeur? Le code ci-dessous montre comment vous pouvez définir la propriété à partir du constructeur, mais en utilisant la réflexion montre qu'il n'y a pas de setter dans les coulisses. Comment est-il défini à partir de l'appel du constructeur si la méthode setter n'existe même pas dans l'IL?C# Propriété sans setter - comment peut-elle être définie à partir du constructeur?

void Main() 
{ 
    var obj = new GetOnlyProperty("original value"); 
    Console.WriteLine(obj.Thing); //works, property gets set from ctor 

    //get the set method with reflection, is it just hidden..? 
    //nope, null reference exception 
    typeof(GetOnlyProperty) 
     .GetProperty("Thing", BindingFlags.Instance | BindingFlags.Public) 
     .GetSetMethod() 
     .Invoke(obj, new object[]{"can't set me to this, setter doen't exist!"}); 
} 

public class GetOnlyProperty 
{ 
    public string Thing { get; } 

    public GetOnlyProperty(string thing) 
    { 
     Thing = thing; 
    } 
} 
+0

auto-propriétés non abstraites utilisez toujours un champ d'accompagnement. La définition de la propriété à l'intérieur de la classe est traduite en définissant le champ de sauvegarde. Événement travail d'une manière similaire. – IllidanS4

Répondre

10

Une propriété implémentée automatiquement en lecture seule est convertie par le compilateur en un champ en lecture seule et en une propriété en lecture seule. Les affectations à la propriété dans le constructeur sont compilées en tant qu'attributions au champ sous-jacent.

donc votre code ici:

public class GetOnlyProperty 
{ 
    public string Thing { get; } 

    public GetOnlyProperty(string thing) 
    { 
     Thing = thing; 
    } 
} 

est compilé dans IL comme si vous aviez écrit:

public class GetOnlyProperty 
{ 
    private readonly string _thing; 
    public string Thing => _thing; 

    public GetOnlyProperty(string thing) 
    { 
     _thing = thing; 
    } 
} 

... sauf que _thing est vraiment donné un "nom indicible" qui wouldn Ne soyez pas un identifiant C# valide.

+0

Pas seulement une réponse complète mais de Jon Skeet lui-même! Incroyable, merci :) – thisextendsthat

+0

Drôle que dans 'vb.net' vous pouvez accéder à ce champ" généré "en ajoutant un trait de soulignement au nom de propriété' _Thing' et même changer la valeur :). – Fabio

+0

@Fabio: Yikes. Heureusement en C# on lui donne un nom comme ' k__BackingField', et le' <> 'le rend invalide comme identifiant. –

0

Parce qu'une propriété en lecture seule doit être affecté à un moment ou un autre, sinon sa valeur serait toujours la valeur par défaut du type, et il serait tout à fait inutile.

Pour les constructeurs (à côté d'autres raisons évidentes), il s'agit d'attribuer des valeurs à des champs en lecture seule.

+0

Ma question est _how_ cela arrive-t-il, dans IL si la méthode setter n'existe pas? Comment le constructeur appelle-t-il l'appel à la propriété fonctionne-t-il réellement, sous les couvertures. – thisextendsthat

2

Une propriété en lecture seule (get only) a un champ de sauvegarde readonly, qui, comme vous le savez probablement, ne peut être défini que dans le constructeur.

donc lorsque vous avez object Property { get; }

cela se traduit

private readonly object _property; 
public object get_Property(){return _property;} 

et le compilateur sait que si vous définissez la propriété dans le constructeur pour définir le champ directement