4

要使用这样的初始化语法:

var contacts = new ContactList
{
    { "Dan", "dan.tao@email.com" },
    { "Eric", "ceo@google.com" }
};

...我的理解是我的ContactList类型需要定义一个带有Add两个string参数的方法:

public void Add(string name, string email);

对此我有点困惑的是,初始化程序语法在创建只读或固定大小的集合时{ }似乎最有用。毕竟它是为了模仿数组的初始化语法,对吧?(好的,所以数组不是只读的;但它们固定大小的。)自然只有在编译时知道集合的内容(至少是元素的数量)时才能使用它。

因此,使用这个集合初始化器语法(有一个方法,因此有一个可变集合)的主要要求似乎Add与它最有用的典型情况不一致。

我确信我没有像 C# 设计团队那样考虑过这个问题;似乎这种语法可能有不同的规则,可以更好地与其典型的使用场景相吻合。

我在这里离基地很远吗?使用语法来初始化固定大小的集合的愿望{ }不像我想的那么普遍吗?还有哪些其他因素可能影响了我根本没有想到的这种语法的要求的制定?

4

9 回答 9

10

我确信我没有像 C# 设计团队那样考虑过这个问题;似乎这种语法可能有不同的规则,可以更好地与其典型的使用场景相吻合。

你的分析非常好;关键问题是上面陈述中的最后三个词。实际的典型使用场景是什么?

集合初始化器的典型使用场景激发的设计目标是使现有集合类型的初始化可以在表达式语法中进行,以便集合初始化器可以嵌入到查询理解中转换为表达式树

其他所有场景的优先级都较低;该功能之所以存在,是因为它有助于使 LINQ 工作。

C# 3 编译器团队是那个版本的 Visual Studio / .NET 的“长杆”——我们的工作时间是所有团队中最多的,这意味着我们每延迟一天,产品就会延迟。我们希望为你们所有人按时交付优质产品,而完美是美好的敌人。是的,这个特性有点笨拙,并不能完全满足你的所有需求,但更重要的是让它变得稳固并针对 LINQ 进行测试,而不是让它适用于大量不可变的集合类型,而这些类型在很大程度上没有甚至存在

如果从一开始就将此功能设计到语言中,而框架类型仍在不断发展,我相信事情会有所不同。正如我们在本网站的其他地方所讨论的那样,我非常希望有一个一次写入多次读取的固定大小的值数组。最好定义一个通用模式来提供一堆状态来初始化任意不可变集合。你是对的,集合初始化器语法对于这样的事情来说是理想的。

诸如此类的功能在潜在的未来虚拟语言版本的列表中,但在列表中并不高。换句话说,在我们为不可变集合初始化考虑过多的语法糖之前,让我们首先获得 async/await。

于 2011-01-14T00:41:09.920 回答
3

这是因为初始化语句是 CLR 的简写。当它被编译成字节码时,它会调用你定义的 Add 方法。

所以你可以证明这个初始化语句并不是真正的“一流”特性,因为它在 IL 中没有对应的特性。但我们使用的很多东西都是这种情况,例如“使用”语句。

于 2011-01-13T14:46:44.063 回答
2

主要原因是语法糖

初始化器语法只会使 C# 中的编程更容易一些。它实际上并没有为语言增加任何表达能力。

如果初始化程序不需要Add()方法,那么它将是一个与现在大不相同的功能。基本上,这不是 C# 的工作方式。没有用于创建通用集合的字面形式。

于 2011-01-13T14:46:04.750 回答
2

严格来说,这不是一个答案,但如果您想知道哪些因素影响了集合初始化器的设计,那么您可能会发现这很有趣:

于 2011-01-13T14:46:08.743 回答
2

原因是它被改造了。我同意你的观点,使用构造函数获取集合会更有意义,但并非所有现有集合类都实现了这一点,并且更改应该(1)适用于所有现有集合,(2)不更改任何现有类方式。

这是一种妥协。

于 2011-01-13T14:55:20.090 回答
1

如果不是Add方法,初始化语法应该使用什么?在运行集合的构造函数并完全创建集合之后,初始化语法是“运行”。在创建集合后,必须有某种方法可以将项目添加到集合中。

如果要初始化只读集合,请在构造函数中执行(带T[] items参数或类似参数)

于 2011-01-13T14:46:09.310 回答
1

据我了解,集合初始化器语法只是语法糖,没有任何特殊技巧。它的设计部分是为了支持在 Linq 查询中初始化集合:

from a in somewhere
select new {
   Something = a.Something
   Collection = new List<object>() {
      a.Item1,
      a.Item2,
      ...
   }
}

在没有办法内联执行此操作之前,您必须在案例之后执行此操作,这很烦人。

于 2011-01-13T14:49:36.493 回答
1

我很想拥有不可变类型(集合和普通类型)的初始化语法。我认为这可以通过特殊的构造函数重载来实现,使用类似于params.

例如这样的:

MyClass(initializer KeyValuePair<K,V>[] initialValues)

但不幸的是,C# 团队还没有实现这样的东西:(

所以我们需要使用类似的解决方法

MyClass(new KeyValuePair<K,V>[]{...})

目前

于 2011-01-13T14:56:48.430 回答
1

集合初始值设定项是表达式,因此可以在只有表达式有效的情况下使用它们,例如字段初始值设定项或 LINQ 查询。这使得它们的存在非常有用。

我还认为花括号 { }类型的初始化,闻起来更像是一个固定大小的集合,但它只是一种语法选择。

于 2011-01-13T15:07:27.197 回答