为什么C#3.0对象初始化构造圆括号可选? [英] Why are C# 3.0 object initializer constructor parentheses optional?

查看:270
本文介绍了为什么C#3.0对象初始化构造圆括号可选?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看来,C#3.0对象初始化语法允许一个排除开/关对圆括号在构造函数时,有现有的参数的构造函数。例如:

It seems that the C# 3.0 object initializer syntax allows one to exclude the open/close pair of parentheses in the constructor when there is a parameterless constructor existing. Example:

var x = new XTypeName { PropA = value, PropB = value };

相对于

var x = new XTypeName() { PropA = value, PropB = value };

我很好奇,为什么构造函数打开/关闭括号对是可选这里经过 XTypeName

推荐答案

更​​新:<一href=\"http://blogs.msdn.com/b/ericlippert/archive/2010/09/20/ambiguous-optional-parentheses.aspx\">This问题是我的博客在2010年9月20日的主题。感谢伟大的问题!

UPDATE: This question was the subject of my blog on September 20th 2010. Thanks for the great question!

乔希经济特区:

尊敬的先生利珀特,给我们的内幕消息:)

Dear Mr. Lippert, Give us the inside scoop :)

首先,你蝙蝠信号的人:如果有你想要的东西引起了我的注意,您可以随时点击我的博客上的联系链接。

First off, all you "bat signal" people: if there is something you want brought to my attention you can always click on the "contact" link on my blog.

二,伙计,利珀特先生是我的的父亲

Second, dude, "Mr. Lippert" is my father.

乔希和乍得的回答(他们增加价值,为什么需要它们?和消除冗余)基本上是正确的。充实了这一点多一点:

Josh and Chad's answers ("they add no value so why require them?" and "to eliminate redundancy") are basically correct. To flesh that out a bit more:

让您的的Elid参数列表作为大功能对象初始化的满足我们的酒吧含糖功能的一部分的功能​​。我们考虑的一些要点:

The feature of allowing you to elide the argument list as part of the "larger feature" of object initializers met our bar for "sugary" features. Some points we considered:


  • 的设计和规范成本低

  • 我们就要被广泛地改变解析器code无论如何,处理对象的创建;相比于较大特征的成本
  • 使得参数列表可选的额外的开发成本并不大
  • 测试负担相比较大特征的成本是相对小的

  • 文档负担相对比较小...

  • 维护负担预计要小;我不记得在多年报道此功能的任何错误,因为它运。

  • 的功能不会造成这方面的功能,未来任何显而易见的风险。 (我们想要做的最后一件事是做一个价格便宜,易于功能现在这使得它更难实现在未来的一个更引人注目的功能。)

  • 的功能添加任何新的含糊的语言的词汇,语法和语义分析。它带来了一种部分节目的分析是由IDE的智能感知引擎,而你打字执行没有问题。等等。

  • 的功能打一个共同的甜蜜点为较大的对象初始化功能;通常,如果您使用的是对象初始化是precisely因为对象的构造做的的允许你设置你想要的属性。这是很常见的这种对象只是财产袋,已在首位的构造函数没有参数。

  • the design and specification cost was low
  • we were going to be extensively changing the parser code that handles object creation anyway; the additional development cost of making the parameter list optional was not large compared to the cost of the larger feature
  • the testing burden was relatively small compared to the cost of the larger feature
  • the documentation burden was relatively small compared...
  • the maintenance burden was anticipated to be small; I don't recall any bugs reported in this feature in the years since it shipped.
  • the feature does not pose any immediately obvious risks to future features in this area. (The last thing we want to do is make a cheap, easy feature now that makes it much harder to implement a more compelling feature in the future.)
  • the feature adds no new ambiguities to the lexical, grammatical or semantic analysis of the language. It poses no problems for the sort of "partial program" analysis that is performed by the IDE's "IntelliSense" engine while you are typing. And so on.
  • the feature hits a common "sweet spot" for the larger object initialization feature; typically if you are using an object initializer it is precisely because the constructor of the object does not allow you to set the properties you want. It is very common for such objects to simply be "property bags" that have no parameters in the ctor in the first place.

更新:詹姆斯问在注释:

UPDATE: James asks in a comment:

那么为什么你是不是也使对象创建前pression,做的默认构造函数调用可选的空括号的的有一个对象初始化?

Why then did you not also make empty parentheses optional in the default constructor call of an object creation expression that does not have an object initializer?

再看看上面标准的列表。其中之一是,该变化不会在程序的词汇,语法或语义分析引入任何新的模糊性。您的建议更改的确实的引入语义分析歧义:

Take another look at that list of criteria above. One of them is that the change does not introduce any new ambiguity in the lexical, grammatical or semantic analysis of a program. Your proposed change does introduce a semantic analysis ambiguity:

class P
{
    class B
    {
        public class M { }
    }
    class C : B
    {
        new public void M(){}
    }
    static void Main()
    {
        new C().M(); // 1
        new C.M();   // 2
    }
}

1行创建了一个新的C,调用默认的构造函数,然后调用新对象的实例方法M.。 2行创建B.M的新实例,并调用其默认构造函数。 如果在第1行括号是可选的,那么第2是模棱两可:我们将不得不拿出一个规则解决歧义;我们不能让一个的错误的,因为那将是改变现有法律的C#程序成破程序重大更改。

Line 1 creates a new C, calls the default constructor, and then calls the instance method M on the new object. Line 2 creates a new instance of B.M and calls its default constructor. If the parentheses on line 1 were optional then line 2 would be ambiguous. We would then have to come up with a rule resolving the ambiguity; we could not make it an error because that would then be a breaking change that changes an existing legal C# program into a broken program.

因此​​,规则必须是非常复杂的:基本上是括号只有在他们不引入歧义的情况下可选。我们不得不分析所有介绍含糊不清,然后在编译器中编写code探测到它们可能情况。

Therefore the rule would have to be very complicated: essentially that the parentheses are only optional in cases where they don't introduce ambiguities. We'd have to analyze all the possible cases that introduce ambiguities and then write code in the compiler to detect them.

有鉴于此,回去看看我提到的所有费用。他们中有多少现在变成大?复杂的规则有很大的设计,规范,开发,测试和文档的成本。复杂的规则更可能导致与在未来的功能产生意外的交互问题。

In that light, go back and look at all the costs I mention. How many of them now become large? Complicated rules have large design, spec, development, testing and documentation costs. Complicated rules are much more likely to cause problems with unexpected interactions with features in the future.

一切为了什么呢? ,增加了新的不重复presentational电源语言,但确实增加了疯狂的极端情况一个小小的客户的利益就等着喊疑难杂症一些不知情的可怜的灵魂谁跑了进去。这样的特点得到削减的立即的装上永远不会做这种列表中。

All for what? A tiny customer benefit that adds no new representational power to the language, but does add crazy corner cases just waiting to yell "gotcha" at some poor unsuspecting soul who runs into it. Features like that get cut immediately and put on the "never do this" list.

更新:詹姆斯问一些后续​​问题,我需要作者的调戏:

UPDATE: James asks some more follow-up questions, which I take authorial liberties with:

你是如何确定特定的歧义?

How did you determine that particular ambiguity?

这一次是立即清除;我是pretty熟悉C#中的规则来确定时,带点名称的预期。

That one was immediately clear; I am pretty familiar with the rules in C# for determining when a dotted name is expected.

在考虑一个新的功能,你怎么确定它是否会导致任何含糊之处?手,正规的证明,经编机的分析,是什么?

When considering a new feature how do you determine whether it causes any ambiguity? By hand, by formal proof, by machine analysis, what?

这三种。主要是我们只看规范和面就可以了,正如我上面一样。例如,假设我们想要一个新的preFIX经营者添加到C#名为FROB

All three. Mostly we just look at the spec and noodle on it, as I did above. For example, suppose we wanted to add a new prefix operator to C# called "frob":

x = frob 123 + 456;

(更新: FROB 当然是的等待;这里的分析基本上是设计团队去分析通过加时等待

(UPDATE: frob is of course await; the analysis here is essentially the analysis that the design team went through when adding await.)

FROB这里就像是新或++ - 它某种类型的前pression之前。我们会制定出所需的precedence和结合等等,然后开始问这样的问题:如果有什么程序已经有一个类型,字段,属性,事件,方法,常量或当地人称FROB?这将立即导致情况下,像:

"frob" here is like "new" or "++" - it comes before an expression of some sort. We'd work out the desired precedence and associativity and so on, and then start asking questions like "what if the program already has a type, field, property, event, method, constant, or local called frob?" That would immediately lead to cases like:

frob x = 10;

这是否意味着做的X = 10的结果,FROB操作,或者创建类型FROB名为x的变量,并指定10吗?

does that mean "do the frob operation on the result of x = 10, or create a variable of type frob called x and assign 10 to it?"

G(frob + x)

这是否意味着FROB x上的一元加运算符的结果或添加前pression FROB为x?

Does that mean "frob the result of the unary plus operator on x" or "add expression frob to x"?

等。要解决这些含糊之处,我们可能会引入启发。当你说变种x = 10;这是不明确的;这可能意味着推断出x的类型,或者它可能意味着x是类型变种。因此,我们有启发:我们首先尝试查找一个名为型变种,且仅当不存在做推断x的类型。

And so on. To resolve these ambiguities we might introduce heuristics. When you say "var x = 10;" that's ambiguous; it could mean "infer the type of x" or it could mean "x is of type var". So we have a heuristic: we first attempt to look up a type named var, and only if one does not exist do we infer the type of x.

或者,我们可能会使得其不含糊改变的语法。当他们设计的C#2.0,他们有这个问题:

Or, we might change the syntax so that it is not ambiguous. When they designed C# 2.0 they had this problem:

yield(x);

这是否意味着产量中的x迭代器或调用带有参数x产量的方法?通过将其更改为

Does that mean "yield x in an iterator" or "call the yield method with argument x?" By changing it to

yield return(x);

现在是明确的。

在对象初始可选括号的情况下,它是简单的原因,是否有引进或不是因为的中是允许引入一些开头的情况下,数{非常小歧义的。基本上只是各种声明环境中,lambda表达式,数组的初始化和仅此而已。这很容易通过所有的案件推理和证明,有没有歧义。确保IDE中保持高效率是有点困难,但可以没有太多的麻烦来完成。

In the case of optional parens in an object initializer it is straightforward to reason about whether there are ambiguities introduced or not because the number of situations in which it is permissible to introduce something that starts with { is very small. Basically just various statement contexts, statement lambdas, array initializers and that's about it. It's easy to reason through all the cases and show that there's no ambiguity. Making sure the IDE stays efficient is somewhat harder but can be done without too much trouble.

这有点摆弄周围的规格通常就足够了。如果它是一个特别棘手的功能,那么我们拿出较重的工具。例如,在设计LINQ,编译球员之一,并且IDE球员谁都有解析器理论背景之一,当自己建造一个解析器生成器,可以分析语法寻找歧义,再喂查询COM $ P提出的C#语法$ phensions进去;这样发现很多情况下,查询是不明确的。

This sort of fiddling around with the spec usually is sufficient. If it is a particularly tricky feature then we pull out heavier tools. For example, when designing LINQ, one of the compiler guys and one of the IDE guys who both have a background in parser theory built themselves a parser generator that could analyze grammars looking for ambiguities, and then fed proposed C# grammars for query comprehensions into it; doing so found many cases where queries were ambiguous.

或者,当我们做了先进的类型推断在C#lambda表达式3.0我们写了我们的建议,然后派他们在池塘微软剑桥研究院那里的语言小组有足够好的工作了正式的证明类型推论建议在理论上的声音。

Or, when we did advanced type inference on lambdas in C# 3.0 we wrote up our proposals and then sent them over the pond to Microsoft Research in Cambridge where the languages team there was good enough to work up a formal proof that the type inference proposal was theoretically sound.

今天在C#中是否有歧义?

Are there ambiguities in C# today?

当然。

G(F<A, B>(0))

在C#1很清楚这意味着什么。这是一样的:

In C# 1 it is clear what that means. It's the same as:

G( (F<A), (B>0) )

也就是说,它有两个参数是布尔变量调用-G。在C#2,这可能意味着什么在C#1的意思,但它也可能意味着0传递给一个类型参数A和B泛型方法F,然后通过F到G的结果。我们增加了一个复杂的启发式算法来决定哪两个情况下,你可能是指解析器。

That is, it calls G with two arguments that are bools. In C# 2, that could mean what it meant in C# 1, but it could also mean "pass 0 to the generic method F that takes type parameters A and B, and then pass the result of F to G". We added a complicated heuristic to the parser which determines which of the two cases you probably meant.

同样,铸件甚至在C#1.0模棱两可的:

Similarly, casts are ambiguous even in C# 1.0:

G((T)-x)

是,投-x以T或在T减去X?再次,我们有一个启发,使一个很好的猜测。

Is that "cast -x to T" or "subtract x from T"? Again, we have a heuristic that makes a good guess.

这篇关于为什么C#3.0对象初始化构造圆括号可选?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆