我最近在 C# 中遇到了一些相当令人困惑的事情。在我们的代码库中,我们有一个 TreeNode
类。在更改一些代码时,我发现无法将变量分配给 Nodes
属性。仔细检查后,很明显该属性是只读的,并且这种行为是可以预料的。
奇怪的是,我们的代码库在此之前一直依赖于将一些匿名类型分配给 Nodes
属性,并且可以完美地编译和运行。
总结一下:为什么 AddSomeNodes
中的赋值首先起作用?
using System.Collections.Generic;
namespace ReadOnlyProperty
{
public class TreeNode
{
private readonly IList<TreeNode> _nodes = new List<TreeNode>();
public IList<TreeNode> Nodes
{
get { return _nodes; }
}
}
public class TreeBuilder
{
public IEnumerable<TreeNode> AddSomeNodes()
{
yield return new TreeNode
{
Nodes = { new TreeNode() }
};
}
public IEnumerable<TreeNode> AddSomeOtherNodes()
{
var someNodes = new List<TreeNode>();
yield return new TreeNode
{
Nodes = someNodes
};
}
}
}
最佳答案
AddSomeNodes
没有创建 List<TreeNode>
的实例因为该语法是一个集合初始化器(因此它没有分配给 Nodes
,这意味着它不会破坏 readonly
契约),编译器实际上将集合初始化器转换为对 .Add
的调用。 .
AddSomeOtherNodes
call 实际上尝试重新分配值,但它是 readonly
.这也是对象初始化器语法,它转化为简单的属性调用。此属性没有 setter,因此该调用会产生编译器错误。尝试添加设置只读值的 setter 将生成另一个编译器错误,因为它被标记为 readonly
。 .
By using a collection initializer you do not have to specify multiple calls to the Add method of the class in your source code; the compiler adds the calls.
另外,澄清一下,您的代码中没有匿名类型在起作用——它都是初始化语法。
与您的问题无关,但属于同一领域。
有趣的是,Nodes = { new TreeNode() }
语法不适用于本地成员,它似乎只在嵌套在对象初始值设定项中或在对象分配期间有效:
List<int> numbers = { 1, 2, 3, 4 }; // This isn't valid.
List<int> numbers = new List<int> { 1, 2, 3, 4 }; // Valid.
// This is valid, but will NullReferenceException on Numbers
// if NumberContainer doesn't "new" the list internally.
var container = new NumberContainer()
{
Numbers = { 1, 2, 3, 4 }
};
MSDN 文档似乎对此没有任何说明。
关于c# - 设置一个匿名类型的只读属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11415162/