为什么我可以将集合初始化程序与其他类的私有集访问一起使用?

11 .net c#

请考虑以下代码:

public sealed class Order
{
    public Order()
    {
        Items = new List<OrderItem>();
    }

    public List<OrderItem> Items { get; private set; }
}

public sealed class OrderItem
{
}
Run Code Online (Sandbox Code Playgroud)

这里是Order另一个类的初始化.

var order = new Order
{
    Items =
    {
        new OrderItem(),
        new OrderItem()
    }
};
Run Code Online (Sandbox Code Playgroud)

你能解释一下它的工作原理吗?当你看到Orderhas private set属性时,我认为不可能设置它的值.

Jus*_*ner 12

您的语句有效,因为集合初始化语法使用该Add()方法将项添加到集合中,而不是将成员设置为集合的新实例.基本上,您的代码相当于:

var order = new Order();
order.Items.Add(new OrderItem());
order.Items.Add(new OrderItem());
Run Code Online (Sandbox Code Playgroud)

这很好,因为你只使用了getter方法.


GSe*_*rjo 7

简短回答:

它通过集合初始化程序来调用Add添加项目

答案很长:

可以通过该方法初始化C#3.0 cpesification,实现IEnumerable具有适当Add方法的对象Add.

Itemspublic get访问器,Items它是一个List<T>实现IEnumerable和拥有Add.以下是编译器查看代码的方式

var order = new Order();
order.Items.Add(new OrderItem());
order.Items.Add(new OrderItem());
Run Code Online (Sandbox Code Playgroud)

请注意,编译器不使用List实现的信息IEnumerable,这里是证明,不会抛出任何异常

public sealed class Order
{
    public Order()
    {
        Items = new MyCollection();
    }

    public MyCollection Items { get; private set; }
}

public sealed class OrderItem
{
}

public class MyCollection : IEnumerable
{
    private readonly List<OrderItem> _items = new List<OrderItem>();

    public void Add(OrderItem item)
    {
        _items.Add(item);
    }

    public IEnumerator GetEnumerator()
    {
        throw new NotImplementedException();
    }
}
Run Code Online (Sandbox Code Playgroud)

来自C#语言规范

应用集合初始值设定项的集合对象必须是实现的类型System.Collections.IEnumerable或发生编译时错误.对于按顺序的每个指定元素,集合初始值设定项在目标对象上调用Add方法,并将元素初始值设定项的表达式列表作为参数列表,为每次调用应用正常的重载决策.因此,集合对象必须包含Add每个元素初始值设定项的适用方法.

  • @Magnus:当时这是一个有争议的决定.我们对具有"Add"方法的类型进行了广泛的研究,发现有两大类:可变集合类和数学类.没有人想进入你可以使用集合初始化程序进行数学运算的情况.区别在于,几乎所有的集合都实现了"IEnumerable"而数学类型没有,所以我们选择了它作为我们的shibboleth. (5认同)
  • 奇怪的是它需要实现`IEnumerable`,因为它没有被集合初始化器使用. (2认同)