C#没有setter的属性 - 它如何从构造函数中设置?

问题描述:

你怎么能从构造函数中设置一个只能得到的自动属性?下面的代码显示了如何从构造函数中设置属性,但使用反射显示幕后真的没有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

只读自动实现的属性由编译器转换为只读字段和只读属性。赋值给构造函数中的属性被编译为基础字段的赋值。

所以,你的代码在这里:

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

我的问题是_how_是否发生,如果setter方法不存在,在IL中?在封面下,构造函数如何设置调用属性的实际工作。 – thisextendsthat

只读属性(仅获取)具有支持readonly的字段,您可能知道该字段只能在构造函数中设置。

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

这相当于

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

和编译器知道,如果你在构造函数中设置的属性设置现场直接