属性 对象初始值设定项中的赋值不被视为与 C# 6 中的自动属性处于同一级别

Property assignments in object initializers not considered on the same level as auto-properties in C# 6

C#6 引入了无需 setter 即可初始化属性的功能,因此现在可以使用这种语法

public class MyClass
{
    public int Answer { get; } = 42;
}

甚至这个

public class MyClass
{
    public int Answer { get; }
    public MyClass() 
    {
        Answer = 42;
    }
}

我知道(或者更确切地说,强烈假设)这将被转换为生成的 readonly 字段,并在 CIL 中使用访问器方法,所以我理解 如何这个

public class MyClass
{
    public int Answer { get; }
    public MyClass CreateMyClassInstance()
    {
        return new MyClass()
        {
            Answer = 42
        };
    }
}

不编译(因为赋值在技术上发生在构造函数之外,这与支持 readonly 字段施加的限制冲突)。

我的问题是 为什么 这种行为首先被禁止?为什么从句法 and/or 编译的角度来看,作为对象初始值设定项一部分的 属性 赋值不仅被视为要在其后执行的额外内联逻辑,而且仍在对象的构造函数中?是设计使然,是技术限制或向后兼容性的结果,还是可能只是一个不够重要的更改?

Why is such a behavior prohibited in the first place?

允许从对象初始值设定项分配只读 属性 会破坏封装。在构造函数中完成的任何初始化稍后都可以被对象初始化程序中的客户端代码覆盖。 类 不可能保持不变量。

这样的功能不仅没有必要,而且很危险。

Why, from a syntactic and/or compilation point of view, are the property assignments that are part of an object initializer not just considered as extra inline logic to execute after, but still within the object's constructor?

这意味着对于每个对象初始值设定项,编译器都必须生成一个新的构造函数。可能修改和破坏另一个程序集中的类型。

或者,newobj CIL 指令必须修改以允许在构造函数之后执行一些任意代码。

除了 Jackub Lortz 所说的,要达到你想要的效果的最佳方法是使用 Answer { get; private set },或者在 C# 6 中,你可以分配一个 readonly 属性 像这样初始化:

int Answer { get; } = 42;

从那时起Answer就是readonly。我假设分配给 Answer 的值必须是一个常数。如果没有,您也许可以进行一些破解。

编辑:

您可以像这样修改您的对象:

public class MyClass
{
    private bool readOnly;

    private int x;
    public int X
    {
        get { return x; }
        set
        {
            if (readOnly) throw new InvalidOperationException();
            else x = value;
        }
    }

    public MyClass()
    {
        X = 42;
        readOnly = true;
    }
}

这已经过测试并且有效。在此代码中,readOnly 可以在类型的任何位置更改,从而允许您更改 X。不过,您可以扩展这个想法,将其创建为 objectinterfacegeneric 类型,它有一个方法 x.MakeReadOnly();,无论如何都无法撤消它,任何尝试这样做都会导致错误。