为什么 IL 设置这个值两次?

Why does the IL set this value twice?

当我输入这段代码时,我正在尝试使用 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 <x>k__BackingField;
    public int x
    {
        [CompilerGenerated]
        get
        {
            return this.<x>k__BackingField;
        }
    }
    public C()
    {
        this.<x>k__BackingField = 5;
        base(); // This is not valid C#, but it represents the IL correctly.

        this.<x>k__BackingField = 4;
    }
}

我不明白的是为什么它会在构造函数中对支持字段进行两次赋值:

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

        this.<x>k__BackingField = 4;. 

这是网站的错误还是 Roslyn 编译器真的这样做了(在我看来真的很愚蠢)?


我的意思是如果我这样做

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

public int x { get; } = 5;

并创建代码:

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

    this.<x>k__BackingField = x;
}

但它不应该优化它吗?

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

public C()
{
    //here
    x = 4;
}

//and here
public int x { get; } = 5;

问题编辑后更新

But shouldn't it optimize that out?

它可能可以,但前提是 class 没有继承自另一个在其构造函数中使用该值的 class,它知道它是一个自动 属性 并且setter 不执行任何其他操作。

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

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

C# 6.0 只读 属性

public int x { get; }

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

编辑

  • 这个问题分为两个部分:一是当前 http://tryroslyn.azurewebsites.net/(截至2016.05.25)编译 DEBUG 模式下的代码,即使在 header 的页面。
  • 其次Roslyn真的没有优化出来 只读 属性 的双重声明,所以如果你使用 VS15 和 在发布模式下编译此代码,x 将被分配两次 嗯

多次初始化只读 属性 的用法示例可以是多个构造函数的用法,其中只有一个重新定义您为 属性 设置的 "default" 值.

但是在您的情况下,优化并不是一个坏主意,可能值得将其作为功能请求提出 Roslyn github page