最近我在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
};
}
}
}
答案 0 :(得分:4)
AddSomeNodes
未创建List<TreeNode>
的实例,因为该语法是集合初始值设定项(因此它不会分配给Nodes
,这意味着它不会破坏readonly
合同),编译器实际上将集合初始化程序转换为对.Add
的调用。
AddSomeOtherNodes
调用实际上会尝试重新分配值,但它是readonly
。这也是对象初始化器语法,它转换为简单的属性调用。此属性没有setter,因此该调用会生成编译器错误。尝试添加设置readonly值的setter将生成另一个编译器错误,因为它标记为readonly
。
通过使用集合初始值设定项,您不必指定多个 在源代码中调用类的Add方法;编译器 添加电话。
另外,为了澄清一下,您的代码中有 没有 匿名类型 - 它是所有初始化程序语法。
<小时/> 与您的问题无关,但在同一地区。
有趣的是,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文档似乎没有任何澄清。
答案 1 :(得分:2)
您的节点属性未被分配。
使用特殊集合初始值设定项:
CollectionProperty = { a, b, c };
更改为:
CollectionProperty.Add(a);
CollectionProperty.Add(b);
CollectionProperty.Add(c);
答案 2 :(得分:1)
这不是指定它是向ICollection
Nodes = {new TreeNode() }, that is why it works.
答案 3 :(得分:1)
我编译了你的代码(在删除AddSomeOtherNodes方法之后)并在Reflector中打开它,结果如下:
public IEnumerable<TreeNode> AddSomeNodes()
{
TreeNode iteratorVariable0 = new TreeNode();
iteratorVariable0.Nodes.Add(new TreeNode());
yield return iteratorVariable0;
}
如您所见,使用此语法,将在Nodes变量上调用Add方法。
答案 4 :(得分:0)
编译器相当于发生的事情:
public IEnumerable<TreeNode> AddSomeNodes()
{
TreeNode node = new TreeNode();
node.Nodes.Add(new TreeNode());
yield return node;
}
这里的重要区别是他们使用集合初始值设定语法来分配值。