为什么C#集合初始化程序以这种方式工作?

时间:2009-01-19 23:47:17

标签: c# collections

我正在查看C#集合初始化程序,发现实现非常实用,但也与C#中的任何其他内容完全不同

我可以创建这样的代码:

using System;
using System.Collections;

class Program
{
    static void Main()
    {
        Test test = new Test { 1, 2, 3 };
    }
}

class Test : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        throw new NotImplementedException();
    }

    public void Add(int i) { }
}

由于我满足了编译器的最低要求(已实现IEnumerablepublic void Add),因此可以正常工作,但显然没有价值。

我想知道是什么阻止了C#团队创建更严格的要求?换句话说,为了编译这种语法,为什么编译器不要求类型实现ICollection?这似乎更符合其他C#功能的精神。

3 个答案:

答案 0 :(得分:90)

您的观察结果显而易见 - 事实上,它反映的是由微软C#语言PM Mads Torgersen制作的。

Mads于2006年10月就这个名为 What Is a Collection? 的主题发表了一篇文章,其中写道:

  

承认,我们在第一次吹响它   用于框架的版本   System.Collections.ICollection,其中   旁边没用了。但是我们修好了   当仿制药出现时很好   在.NET framework 2.0中:   了System.Collections.Generic.ICollection< T>   允许您添加和删除元素,   枚举它们,统计它们并检查   为会员。

     

从那时起,显然每个人都会   实现ICollection< T>每次   他们收藏了吧?不是这样。   以下是我们如何使用LINQ学习   关于什么样的集合真的是,和   这是如何让我们改变我们的语言   在C#3.0中设计。

事实证明,框架中只有ICollection<T>的14个实现,但实现IEnumerable的189个类具有公共Add()方法。

这种方法有一个隐藏的好处 - 如果它们基于ICollection<T>接口,那么就会有一种支持Add()方法。

相反,他们采取的方法意味着集合的初始化器只是形成Add()方法的参数集。

为了说明,让我们稍微扩展您的代码:

class Test : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        throw new NotImplementedException();
    }

    public void Add(int i) { }

    public void Add(int i, string s) { }
}

你现在可以这样写:

class Program
{
    static void Main()
    {
        Test test 
            = new Test 
            {
                1, 
                { 2, "two" },
                3 
            };
    }
}

答案 1 :(得分:9)

我也考虑过这个问题,最让我满意的答案是ICollection除Add之外还有很多方法,例如:Clear,Contains,CopyTo和Remove。删除元素或清除与能够支持对象初始化程序语法无关,您只需要一个Add()。

如果框架的设计足够精细,并且有一个ICollectionAdd接口,那么它将具有“完美”的设计。但老实说,我不认为这会增加很多价值,每个界面都有一个方法。 IEnumerable + Add似乎是一种hackish方法,但是当你想到它时,它是一个更好的选择。

编辑:这不是C#解决此类解决方案问题的唯一时间。从.NET 1.1开始,foreach使用duck类型来枚举集合,所有类需要实现的是GetEnumerator,MoveNext和Current。 Kirill Osenkov有一个post,也会问你的问题。

答案 2 :(得分:3)

(我知道我迟到了3年,但我对现有答案并不满意。)

  

为了编译这种语法,为什么编译器没有   要求类型实现ICollection?

我会颠倒你的问题:如果编译器有非真正需要的要求会有什么用处?

ICollection类也可以从集合初始化程序语法中受益。考虑允许向其中添加数据的类,而不允许访问以前添加的数据。

就个人而言,我喜欢使用new Data { { ..., ... }, ... }语法为我的单元测试代码添加类似DSL的外观。

实际上,我宁愿削弱要求,这样我就可以使用漂亮的语法,甚至不用费心去实现IEnumerable。集合初始化器是Add()的纯语法糖,它们不需要任何其他东西。

相关问题