设置具有匿名类型的只读属性

时间:2012-07-10 14:09:55

标签: c# .net

最近我在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
             };
        }
    }
}

5 个答案:

答案 0 :(得分:4)

AddSomeNodes未创建List<TreeNode>的实例,因为该语法是集合初始值设定项(因此它不会分配给Nodes,这意味着它不会破坏readonly合同),编译器实际上将集合初始化程序转换为对.Add的调用。

AddSomeOtherNodes调用实际上会尝试重新分配值,但它是readonly。这也是对象初始化器语法,它转换为简单的属性调用。此属性没有setter,因此该调用会生成编译器错误。尝试添加设置readonly值的setter将生成另一个编译器错误,因为它标记为readonly

From MSDN

  

通过使用集合初始值设定项,您不必指定多个   在源代码中调用类的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;
}

这里的重要区别是他们使用集合初始值设定语法来分配值。