2017-09-23 34 views
2

你怎麼能從構造函數中設置一個只能得到的自動屬性?下面的代碼顯示瞭如何從構造函數中設置屬性,但使用反射顯示幕後真的沒有setter。如果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; 
    } 
} 

...除了_thing真的發出 「無法形容的名字」 即止跌不是有效的C#標識符。

+0

不僅僅是一個徹底的答案,而是來自Jon Skeet本人!令人驚歎的,謝謝:) – thisextendsthat

+0

有趣的是,在'vb.net'你可以通過向屬性名稱_Thing'添加下劃線來訪問該「生成」字段,甚至改變值:)。 – Fabio

+0

@Fabio:喔。幸運的是,在C#中,其名稱爲' k__BackingField',並且'<>'使其作爲標識符無效。 –

0

因爲只讀屬性應在同一時間或其他指定,否則其價值將永遠是該類型的默認值,這將是完全無用的。

這是構造函數用於(除了其他明顯的原因外),將值分配給只讀字段。

+0

我的問題是_how_是否發生,如果setter方法不存在,在IL中?在封面下,構造函數如何設置調用屬性的實際工作。 – thisextendsthat

2

只讀屬性(僅獲取)具有支持readonly的字段,您可能知道該字段只能在構造函數中設置。

因此,當你有object Property { get; }

這相當於

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

和編譯器知道,如果你在構造函數中設置的屬性設置現場直接

相關問題