2017-09-23 16 views
2

どのようにして、コンストラクタから取得専用の自動プロパティを設定できますか?以下のコードは、コンストラクタからプロパティを設定する方法を示していますが、リフレクションを使用すると、本当にシーンの背後にセッターがないことがわかります。 setterメソッドがILにも存在しない場合は、コンストラクタ呼び出しからどのように設定されますか?C#setterのないプロパティ - コンストラクタからどのようにセットを取得できますか?

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

非抽象自動プロパティフィールドを設定することを知っています常にバッキングフィールドを使用します。クラス内のプロパティの設定は、バッキングフィールドの設定に変換されます。イベントも同様に動作します。 – IllidanS4

答えて

10

読み取り専用の自動実装プロパティは、コンパイラによって読み取り専用フィールドと読み取り専用プロパティに変換されます。コンストラクタのプロパティへの代入は、基礎となるフィールドへの代入としてコンパイルされます。あなたが書いたかのように

public class GetOnlyProperty 
{ 
    public string Thing { get; } 

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

ILにコンパイルされています:

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

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

... wouldnということ_thingが本当に "言いようのない名前を" 与えられている以外だからここにあなたのコードが

有効なC#識別子である必要はありません。

+0

徹底的な回答だけでなく、Jon Skeet自身からも!驚くべきこと、ありがとう:) – thisextendsthat

+0

おかしいことに、 'vb.net'では、プロパティ名' _Thing'にアンダースコアを加え、値を変更することによってその "生成された"フィールドにアクセスできます:) – Fabio

+0

@Fabio:Yikes。幸いにもC#では ' k__BackingField'のような名前が与えられ、' <> 'は識別子として無効にします。 –

0

読み取り専用のプロパティは、そうでない場合、その値は常にタイプのデフォルト値になり、それは完全に役に立たないだろう、時間または別で割り当てる必要がありますので。

これは、(他の明白な理由のほかにも)読み取り専用フィールドに値を割り当てるコンストラクタです。

+0

私の質問は_how_ですが、セッターメソッドが存在しない場合はILでそれが起こりますか?どのようにしてコンストラクタがプロパティの呼び出しを実際には、カバーの下で動作しますか? – thisextendsthat

2

読み取り専用のプロパティ(取得のみ)には、背後のreadonlyフィールドがあります。このフィールドは、おそらく分かっているとおり、コンストラクタでのみ設定できます。

あなたはobject Property { get; }

を持っているので、とき、これは

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

に変換し、コンパイラは、コンストラクタでプロパティを設定した場合、直接

関連する問題