C#对象初始值设定项将初始化只读属性,但仅限于非原语类型

C#对象初始值设定项将初始化只读属性,但仅限于非原语类型,c#,primitive-types,reference-type,object-initializers,C#,Primitive Types,Reference Type,Object Initializers,在下面的测试代码中,我不明白为什么TestMethod的第一行是合法的,但剩下的两行不是: 公共类栏 { 公共字符串属性{get;set;} } 公开课Foo { 公共int原语{get;}=0; 公共函数{get;}=(i)=>i; 公共条{get;}=新条(); } 公共类TestClass { 公共void TestMethod() { var baz=newfoo{Bar={Prop=“helloworld!”};//合法 var buzz=new Foo{Primitive=1};//

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

公共类栏
{
公共字符串属性{get;set;}
}
公开课Foo
{
公共int原语{get;}=0;
公共函数{get;}=(i)=>i;
公共条{get;}=新条();
}
公共类TestClass
{
公共void TestMethod()
{
var baz=newfoo{Bar={Prop=“helloworld!”};//合法
var buzz=new Foo{Primitive=1};//无法将属性或索引器'Foo.Primitive'分配给--它是只读的
var fuzz=new Foo{Function=(i)=>2};//无法将属性或索引器'Foo.Function'分配给--它是只读的
}
}
如果在对象初始值设定项中为类类型指定只读属性(如
Bar
)是合法的(事实就是这样;这是有意义的,因为在C#中“只读”实际上意味着“除类构造时外的只读”)那么,为什么将诸如
int
Func
之类的类型指定给属性是非法的呢

这似乎更令人困惑,因为(我的理解是)
Func
是一种引用类型,与
Bar
属性类似,但与
int
属性不同。

var baz=new Foo{Bar={Prop=“Hello World!”};//合法的
这不是对
条的赋值。基本上是:

var tmp=newfoo();
tmp.Bar.Prop=“你好,世界!”;
var baz=tmp;
在任何点上都没有将
.Bar
分配给

然而,反过来说:

var buzz=newfoo{Primitive=1};
是:

var tmp=newfoo();
tmp.Primitive=1;
var=tmp;
指定给
.Primitive

如果在对象初始值设定项(即[…])中为类类型指定只读属性(如Bar)是合法的

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

var buzz = new Foo { Primitive = 1 };
这只是语法上的糖分:

var buzz = new Foo();
buzz.Primitive = 1;
如果
基元
是只读属性,则该属性无效

(非常迂腐的一点是,通常更适合将其视为赋值给一个临时局部变量,设置属性,然后在最后赋值给
buzz
,但我们现在将忽略这一点。)

您观察到的代码并没有设置这些只读属性,而是获取它们,然后使用返回的引用设置值。因此:

var baz = new Foo { Bar = { Prop = "Hello World!" } }
实际上相当于:

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

这是完全正确的,即使
Bar
是只读的。

令人困惑的是,语法暗示
Bar={…}
本身就是一个赋值,而不是。对象初始值设定项是设置相关对象的属性的缩写,而不是属性本身。这不是原始与非原始的问题
newfoo{Bar=null}
同样是非法的。谢谢@jeroenmoster!是的,语法确实暗示了这一点,这确实是我感到困惑的地方!我想知道(正如我在下面问@JonSkeet的那样)在C中还有其他地方吗?#
a=…
没有分配给
a
?!?快速检查一下语法,我就可以暂时说“不”。在LINQ查询中,从技术上讲,
让[id]=[value]
不是赋值,但它最终会转化为赋值,所以这并不重要。还有一些非赋值用法是
=
(比如
使用[alias]=[namespace].[type]
),但它们发生在明显不同的上下文中。如果你真的想绝对肯定地知道,你可以把它作为一个后续问题。:-)哦,这里还有一个:一个可选的参数声明(
voidfoo(inta=0)
)实际上并不分配任何东西,不管它的外观如何;相反,像
foo()
这样的调用将(在调用方站点)扩展到
foo(0)
。可以说,这是另一个模糊语义实际上很有帮助的例子,因为大多数人在将其视为任务时不会感到困惑。(但知道不是这样还是很好的,因此您可以解释如果对
foo
的签名进行更改会发生什么情况)@jeroenmoster-非常感谢!我想你是先回答的,但因为这是一个评论而不是一个答案,所以我不能选择接受这一个;非常感谢。我已经或多或少地看到了这是怎么回事,因为张贴了不久前!但是,
Bar={Prop=“Hello World!”}
语法是怎么回事?在C#中还有其他地方
a=b
没有分配给
a
(如果我还没有完全搞清楚(!)这里发生了什么事的话)吗?你和@MarcGravel的答案都是完全正确的、有帮助的、切中要害的-但我不能接受两个!非常感谢您在这里为Stack Overflow社区所做的一切!感谢你自己,@JonSkeet和@jeroemostert在评论中给出了非常迅速和有用的答案。我必须说,
Bar={Prop=“Hello World!”}
语法非常混乱,因为在这种情况下,
Bar=…
根本不是
Bar
的赋值!还是我还是很困惑@Mikebaton重要的区别是
Bar={…}
vs
Bar=new类型{…}
——第二个是对
Bar
的赋值。是的,我同意这是令人困惑的,但a:我想不出更好的表达方式,b:即使我可以,那艘船已经航行很久了。
Bar.Prop=“Hello World!”
似乎是一种更直观的语法来描述正在发生的事情;但后来我发现我可以放置多个属性。所以也许
Bar{Prop=“Hello World!”,Prop2=“再见残酷的世界,我今天要离开你,再见,再见,再见”}
w