Spo*_*ock 10 .net c# intermediate-language c#-6.0
在C#6之前,属性的初始化不使用支持字段来初始化默认值.在C#6中,它使用支持字段来初始化新的自动初始化属性.
我很好奇为什么在C#6 IL之前使用属性定义进行初始化.这有什么特别的原因吗?或者在C#6之前没有正确实施?
在C#6.0之前
public class PropertyInitialization
{
public string First { get; set; }
public string Last { get; set; }
public PropertyInitialization()
{
this.First = "Adam";
this.Last = "Smith";
}
}
Run Code Online (Sandbox Code Playgroud)
编译器生成代码(IL表示)
public class PropertyInitialisation
{
[CompilerGenerated]
private string \u003CFirst\u003Ek__BackingField;
[CompilerGenerated]
private string \u003CLast\u003Ek__BackingField;
public string First
{
get
{
return this.\u003CFirst\u003Ek__BackingField;
}
set
{
this.\u003CFirst\u003Ek__BackingField = value;
}
}
public string Last
{
get
{
return this.\u003CLast\u003Ek__BackingField;
}
set
{
this.\u003CLast\u003Ek__BackingField = value;
}
}
public PropertyInitialisation()
{
base.\u002Ector();
this.First = "Adam";
this.Last = "Smith";
}
}
Run Code Online (Sandbox Code Playgroud)
C#6
public class AutoPropertyInitialization
{
public string First { get; set; } = "Adam";
public string Last { get; set; } = "Smith";
}
Run Code Online (Sandbox Code Playgroud)
编译器生成代码(IL表示)
public class AutoPropertyInitialization
{
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string \u003CFirst\u003Ek__BackingField;
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string \u003CLast\u003Ek__BackingField;
public string First
{
get
{
return this.\u003CFirst\u003Ek__BackingField;
}
set
{
this.\u003CFirst\u003Ek__BackingField = value;
}
}
public string Last
{
get
{
return this.\u003CLast\u003Ek__BackingField;
}
set
{
this.\u003CLast\u003Ek__BackingField = value;
}
}
public AutoPropertyInitialization()
{
this.\u003CFirst\u003Ek__BackingField = "Adam";
this.\u003CLast\u003Ek__BackingField = "Smith";
base.\u002Ector();
}
}
Run Code Online (Sandbox Code Playgroud)
我很好奇为什么在C#6 IL之前使用属性定义进行初始化.这有什么特别的原因吗?
因为通过自动属性初始化设置值并在构造函数中设置值是两回事.他们有不同的行为.
回想一下,属性是包含字段的访问器方法.所以这一行:
this.First = "Adam";
Run Code Online (Sandbox Code Playgroud)
相当于:
this.set_First("Adam");
Run Code Online (Sandbox Code Playgroud)
你甚至可以在Visual Studio中看到这个!尝试public string set_First(string value)在类中编写带有签名的方法,并观察编译器抱怨你踩到它的脚趾.
就像方法一样,这些可以在子类中重写.看看这段代码:
public class PropertyInitialization
{
public virtual string First { get; set; }
public PropertyInitialization()
{
this.First = "Adam";
}
}
public class ZopertyInitalization : PropertyInitialization
{
public override string First
{
get { return base.First; }
set
{
Console.WriteLine($"Child property hit with the value: '{0}'");
base.First = value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,该行将this.First = "Adam"调用子类中的setter.因为你正在调用一种方法,还记得吗?如果编译器将此方法调用解释为对支持字段的直接调用,则它不会最终调用子setter.编译代码的行为会改变程序的行为.不好!
自动属性是不同的.让我们使用auto-property初始值设定项来改变第一个例子:
public class PropertyInitialization
{
public virtual string First { get; set; } = "Adam";
}
public class ZopertyInitalization : PropertyInitialization
{
public override string First
{
get { return base.First; }
set
{
Console.WriteLine($"Child property hit with the value: '{0}'");
base.First = value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用此代码,将不会调用子类中的setter方法.这是故意的.自动属性初始值设定项用于直接设置支持字段.它们的外观和行为类似于字段初始化程序,这就是为什么我们甚至可以在没有setter的属性上使用它们,如下所示:
public string First { get; } = "Adam";
Run Code Online (Sandbox Code Playgroud)
这里没有setter方法!我们必须直接访问支持字段才能执行此操作.自动属性允许程序员创建不可变值,同时仍然可以从良好的语法中受益.