我正在查看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) { }
}
由于我满足了编译器的最低要求(已实现IEnumerable
和public void Add
),因此可以正常工作,但显然没有价值。
我想知道是什么阻止了C#团队创建更严格的要求?换句话说,为了编译这种语法,为什么编译器不要求类型实现ICollection
?这似乎更符合其他C#功能的精神。
答案 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()的纯语法糖,它们不需要任何其他东西。