为什么 { } 初始化需要 Add 方法?
要使用这样的初始化语法:
var contacts = new ContactList
{
{ "Dan", "[email protected]" },
{ "Eric", "[email protected]" }
};
...我的理解是我的 ContactList
类型 需要定义一个带有两个 string
参数的 Add
方法 :
public void Add(string name, string email);
令我感到有点困惑的是,{ }
初始化语法似乎在创建只读或固定大小集合时最有用。毕竟它是为了模仿数组的初始化语法,对吧? (好吧,所以数组不是只读的;但是它们是固定大小的。)自然地,它只能在编译时已知集合内容(至少元素数量)的情况下使用。
因此,使用此集合初始值设定项语法的主要要求(具有 Add 方法,因此是可变集合)似乎与它最有用的典型情况不一致。
我确信我没有像 C# 设计团队那样对这个问题考虑得那么多;似乎这种语法可能有不同的规则,可以更好地适应其典型的使用场景。
我在这里离基地很远吗?使用 { }
语法来初始化固定大小集合的愿望并不像我想象的那么普遍吗?还有哪些其他因素可能影响了我根本没有想到的这种语法要求的制定?
To use initialization syntax like this:
var contacts = new ContactList
{
{ "Dan", "[email protected]" },
{ "Eric", "[email protected]" }
};
...my understanding is that my ContactList
type would need to define an Add
method that takes two string
parameters:
public void Add(string name, string email);
What's a bit confusing to me about this is that the { }
initializer syntax seems most useful when creating read-only or fixed-size collections. After all it is meant to mimic the initialization syntax for an array, right? (OK, so arrays are not read-only; but they are fixed size.) And naturally it can only be used when the collection's contents are known (at least the number of elements) at compile-time.
So it would almost seem that the main requirement for using this collection initializer syntax (having an Add
method and therefore a mutable collection) is at odds with the typical case in which it would be most useful.
I'm sure I haven't put as much thought into this matter as the C# design team; it just seems that there could have been different rules for this syntax that would have meshed better with its typical usage scenarios.
Am I way off base here? Is the desire to use the { }
syntax to initialize fixed-size collections not as common as I think? What other factors might have influenced the formulation of the requirements for this syntax that I'm simply not thinking of?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
我希望拥有不可变类型(集合和普通类型)的初始值设定项语法。我认为这可以通过使用类似于
params
的语法的特殊构造函数重载来实现。例如这样的事情:
但不幸的是 C# 团队还没有实现这样的事情:(
所以我们需要使用像
现在这样的解决方法
I'd love to have the initializer syntax for immutable types(both collections and normal types). I think this could be implemented with a special constructor overload using a syntax similar to
params
.For example something like this:
But unfortunately the C# team didn't implement such a thing yet :(
So we need to use a workaround like
for now
集合初始值设定项是表达式,因此可以在只有表达式有效的情况下使用它们,例如字段初始值设定项或 LINQ 查询。这使得它们的存在非常有用。
我还认为大括号
{ }
类型的初始化,听起来更像是固定大小的集合,但这只是一种语法选择。Collection initializers are expressions, so they can be used where only expression are valid, such as a field initializer or LINQ query. This makes their existence very useful.
I also think the curly-bracketed
{ }
kind of initialization, smells more like a fixed size collection, but it's just a syntax choice.你的分析非常好;关键问题是上面陈述中的最后三个词。实际的典型使用场景是什么?
集合初始化器的典型使用场景激发的设计目标是使现有集合类型的初始化可以在表达式语法中实现,以便集合初始化器可以嵌入到查询推导式中或转换为表达式树。
其他所有场景的优先级都较低; 该功能之所以存在,是因为它有助于 LINQ 工作。
C# 3 编译器团队是该版本 Visual Studio / .NET 的“长杆” - 我们的日程安排中的工作时间最长对于任何团队来说,这意味着我们每延迟一天,产品就会延迟。我们希望为大家准时交付优质产品,而完美是优秀的敌人。是的,这个功能有点笨拙,并且不能完成您可能想要的所有功能,但使其可靠并针对 LINQ 进行测试比使其适用于一堆基本上不可变的集合类型更重要甚至存在。
如果这个功能从一开始就被设计到语言中,当框架类型仍在发展时,我确信事情会有所不同。正如我们在本网站其他地方讨论的那样,我非常希望有一个一次写入多次读取的固定大小值数组。最好定义一个通用模式来提供一堆状态来初始化任意不可变集合。你是对的,集合初始化语法对于这样的事情来说是理想的。
类似的功能在未来潜在的假设语言版本的列表中,但并不是真正的高位。换句话说,在我们过多考虑不可变集合初始化的语法糖之前,让我们首先正确理解 async/await。
Your analysis is very good; the key problem is the last three words in the statement above. What are the actual typical usage scenarios?
The by-design goal motivated by typical usage scenarios for collection initializers was to make initialization of existing collection types possible in an expression syntax so that collection initializers could be embedded in query comprehensions or converted to expression trees.
Every other scenario was lower priority; the feature exists at all because it helps make LINQ work.
The C# 3 compiler team was the "long pole" for that release of Visual Studio / .NET - we had the most days of work on the schedule of any team, which meant that every day we delayed, the product would be delayed. We wanted to ship a quality product on time for all of you guys, and the perfect is the enemy of the good. Yes, this feature is slightly clunky and doesn't do absolutely everything you might want it to, but it was more important to get it solid and tested for LINQ than to make it work for a bunch of immutable collection types that largely didn't even exist.
Had this feature been designed into the language from day one, while the frameworks types were still evolving, I'm sure that things would have gone differently. As we've discussed elsewhere on this site, I would dearly love to have a write-once-read-many fixed size array of values. It would be nice to define a common pattern for proffering up a bunch of state to initialize an arbitrary immutable collection. You are right that the collection initializer syntax would be ideal for such a thing.
Features like that are on the list for potential future hyptothetical language versions, but not real high on the list. In other words, let's get async/await right first before we think too hard about syntactic sugars for immutable collection initialization.
这是因为初始化语句是 CLR 的简写。当它被编译成字节码时,它将调用您定义的 Add 方法。
因此,您可以证明此初始化语句并不是真正的“一流”功能,因为它在 IL 中没有对应的功能。但我们使用的很多东西都是这种情况,例如“using”语句。
It's because the initialization statement is shorthand for the CLR. When it gets compiled into bytecode, it will call the Add method you've defined.
So you can make the case that this initialization statement is not really a "first class" feature, because it doesn't have a counterpart in IL. But that's the case for quite a lot of what we use, the "using" statement for example.
造成这种情况的原因是它被改装了。我同意你的观点,使用构造函数获取集合会更有意义,但并非所有现有集合类都实现了这一点,并且更改应该(1)适用于所有现有集合,(2)不更改任何集合中的现有类方式。
这是一种妥协。
The reason for this is that it was retrofitted. I agree with you that using a constructor taking a collection would make vastly more sense, but not all of the existing collection classes implemented this and the change should (1) work with all existing collections, (2) not change the existing classes in any way.
It’s a compromise.
主要原因是语法糖。
初始化语法只会让用 C# 编写程序变得更容易一些。它实际上并没有给语言增加任何表达能力。
如果初始化器不需要
Add()
方法,那么它将是一个与现在截然不同的功能。基本上,这不是 C# 的工作原理。没有用于创建一般集合的字面形式。The main reason is Syntactic Sugar.
The initializer syntax only makes writing programing in C# a bit easier. It doesn't actually add any expressive power to the language.
If the initializer didn't require an
Add()
method, then it would be a much different feature than it is now. Basically, it's just not how C# works. There is no literal form for creating general collections.严格来说,这不是一个答案,但如果您想知道哪些因素影响了集合初始化程序的设计,那么您可能会发现这个很有趣:
马口Mads Torgersen]Not an answer, strictly speaking, but if you want to know what sort of things influenced the design of collection initialisers then you'll probably find this interesting:
the Horse's mouthMads Torgersen]如果不是
Add
方法,初始化语法应该使用什么?运行集合的构造函数并完全创建集合后,初始化语法为“运行”。创建集合后,必须有某种方式将项目添加到集合中。如果要初始化只读集合,请在构造函数中执行此操作(采用
T[] items
参数或类似参数)What should the initialization syntax use, if not an
Add
method? The initialization syntax is 'run' after the constructor of the collection is run, and the collection fully created. There must be some way of adding items to the collection after it's been created.If you want to initialize a read-only collection, do it in the constructor (taking a
T[] items
argument or similar)据我了解,集合初始值设定项语法只是语法糖,没有其中有特殊的技巧。它的设计部分是为了支持在 Linq 查询中初始化集合:
之前没有办法内联执行此操作,您必须在 case 之后执行此操作,这很烦人。
As far as I understand it, the collection initializer syntax is just syntactic sugar with no special tricks in it. It was designed in part to support initializing collections inside Linq queries:
Before there was no way to do this inline and you'd have to do it after the case, which was annoying.