为什么IL将此值设置两次?

当我输入这段代码时,我尝试使用Try Roslyn :

using System; using System.Linq; using System.Collections.Generic; using Microsoft.CSharp; public class C { public C() { x = 4; } public int x { get; } = 5; } 

它给了我这个代码:

 using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; [assembly: AssemblyVersion("0.0.0.0")] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [module: UnverifiableCode] public class C { [DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated] private readonly int k__BackingField; public int x { [CompilerGenerated] get { return this.k__BackingField; } } public C() { this.k__BackingField = 5; base(); // This is not valid C#, but it represents the IL correctly. this.k__BackingField = 4; } } 

我没有得到的是为什么它会在构造函数内两次分配支持字段:

  this.k__BackingField = 5; base(); // This is not valid C#, but it represents the IL correctly. this.k__BackingField = 4;. 

这是网站的错误还是Roslyn编译器实际上是这样做的(真是愚蠢的imo)?


我的意思是,如果我这样做

  public C(int x) { this.x = x; } public int x { get; } = 5; 

并创建该代码:

 public C(int x) { this.k__BackingField = 5; base(); // This is not valid C#, but it represents the IL correctly. this.k__BackingField = x; } 

但它不应该优化出来吗?

原因是您在代码中设置了两次,无论是在属性声明中还是在构造函数中。

C#6.0只读属性

 public int x { get; } 

就像关于值赋值的只读字段一样工作:您可以在构造函数中或在声明的位置设置它。

编辑

  • 这个问题分为两部分:首先,当前http://tryroslyn.azurewebsites.net/ (截至2016.05.25)在DEBUG模式下编译代码,即使在页面标题处选择了Release选项。
  • 其次,Roslyn确实没有优化readonly属性的双重声明,所以如果你使用VS15并在发布模式下编译这个代码,那么x也会被分配两次

使用多次初始化readonly属性的示例可以是多个构造函数的使用,其中只有一个重新定义为属性设置的“默认”值。

但是在你的情况下,优化不是一个坏主意,可能值得在Roslyn github页面上将其作为一个function请求提出

因为您在代码中设置了两次:

 public C() { //here x = 4; } //and here public int x { get; } = 5; 

编辑问题后更新

但它不应该优化出来吗?

它可能,但只有当该类不从其构造函数中使用该值的另一​​个类inheritance时,它才知道它是一个自动属性,而setter不会做任何其他事情。

那将是很多(危险的)假设。 在进行这样的优化之前,编译器需要检查很多东西。