C# 对象初始化程序将初始化只读属性,但仅适用于非原始类型

C# object initializer will initialize read only properties, but for non-primitive types only

在下面的测试代码中我不明白为什么第一行TestMethod是合法的,而剩下的两行是不合法的:

public class Bar
{
    public string Prop { get; set; }
}

public class Foo
{
    public int Primitive { get; } = 0;
    public Func<int, int> Function { get; } = (i) => i;
    public Bar Bar { get; } = new Bar();
}

public class TestClass
{
    public void TestMethod()
    {
        var baz = new Foo { Bar = { Prop = "Hello World!" } }; // legal
        var buzz = new Foo { Primitive = 1 }; // Property or indexer 'Foo.Primitive' cannot be assigned to -- it is read only
        var fuzz = new Foo { Function = (i) => 2 }; // Property or indexer 'Foo.Function' cannot be assigned to -- it is read only
    }
}

如果在对象初始值设定项中分配给 class 类型的只读属性如 Bar 是合法的(它是;这是有道理的,因为 'read only' 确实意味着'read only except at class construction time' 在 C# 中,据我所知)那么为什么分配给类型为 intFunc<int, int> 的属性是非法的?

这似乎更加令人困惑,因为(再次,据我了解)Func<int, int> 是引用类型,如 Bar 属性 但不同于 int 属性.

var baz = new Foo { Bar = { Prop = "Hello World!" } }; // legal

这不是对 Bar 分配 。它本质上是:

var tmp = new Foo();
tmp.Bar.Prop = "Hello World!";
var baz = tmp;

.Bar 从未分配给。

相反,然而:

var buzz = new Foo { Primitive = 1 };

是:

var tmp = new Foo();
tmp.Primitive = 1;
var buzz = tmp;

分配给 .Primitive

If it is legal to assign to class-type read only properties like Bar in an object initializer (which it is [...])

不,不是。对象初始值设定项调用构造函数,然后分配给属性。例如,这段代码:

var buzz = new Foo { Primitive = 1 };

只是语法糖:

var buzz = new Foo();
buzz.Primitive = 1;

如果 Primitive 是只读 属性,则无效。

(说句迂腐话,一般认为是赋值给一个临时局部变量,设置属性,最后赋值给buzz更合适,但是我们忽略现在。)

您观察到的工作代码并未设置那些只读属性 - 它是 获取 它们,然后使用返回的引用设置值。所以这个:

var baz = new Foo { Bar = { Prop = "Hello World!" } }

实际上等同于:

var baz = new Foo();
baz.Bar.Prop "Hello World!";

这是完全有效的,即使 Bar 是只读的。