2010 年 9 月 22 日更新:
我怀疑除了 Timwi 之外还有人会读到这篇文章。即便如此,我还是想对这个答案进行一些编辑,因为新的答案现已被接受,并且关于规范引用的摘录是否正确的争论仍在继续(至少在我可能想象的世界中)在技术上是多余的。我没有添加太多内容,但内容太多,无法发表评论。大部分更新可以在标题下找到“转换涉及dynamic
type" below.
2010 年 9 月 19 日更新:
在您的评论中:
[这没有道理。
该死的,蒂姆维,你这么说a lot。但好吧,那么;你让我处于守势,所以开始吧!
免责声明:我有当然不尽可能仔细地检查规范。根据您最近提出的一些问题,您似乎最近对此进行了相当多的研究。这自然会让你比 SO 上的大多数用户更熟悉很多细节;因此,就像您可能从埃里克·利珀特以外的任何人那里收到的大多数答案一样,这可能不会令您满意。
不同场所
首先,你的问题的前提是,如果突出显示的陈述是多余的,那么他们不服务purpose。我的回答的前提是,如果多余的陈述澄清了一些事情,那么它们并不一定是没有目的的。对每个人来说并不明显。这些都是矛盾的前提。如果我们不能在前提上达成一致,我们就无法进行简单的逻辑论证。我只是要求你重新考虑你的前提。
然而,你的回应是重申你的前提是:“如果这些句子确实是多余的,那么它们只会让读者感到困惑,而不会澄清任何事情。”
(顺便说一句,我喜欢你如何将自己设置为该规范的所有读者的代表。)
确切地说,我不能责怪你担任这个职位。我的意思是,确实如此seem明显的。而且我在原来的回答中没有给出任何具体的例子。所以下面我将尝试包括一些具体的例子。但首先,让我退后一步,提出我的看法,解释为什么会出现这种奇怪的现象身份转换概念首先存在于规范中。
目的身份转换定义
乍一看,这个定义似乎相当多余。这不是说任何类型 T 的实例都可以转换为……好吧,转换为 T 吗?是的。但我假设*该定义的目的是为规范提供适当的词汇来利用以下概念:类型标识在讨论的背景下转换.
This allows for statements about conversions which are essentially transitive in nature. The first point you quoted from the spec as an example of a tautological statement falls into this category. It says that if an implicit conversion is defined for some type (I'll call it K) to another type T0 and T0 has an identity conversion to T, then K is implicitly convertible to T. By the definition of identity conversion given above, "has an identity conversion to" really means "is the same type as." So the statement is redundant.
But again: the identity conversion definition exists in the first place to equip the spec with a formal language for describing conversions without having to say things like "if T0 and T are really the same type."
好的,是时候看具体例子了。
存在隐式转换的地方might不明显some开发商
Note: A 好多了Eric Lippert 在中提供了示例他对问题的回答 https://stackoverflow.com/questions/3736789/question-regarding-implicit-conversions-in-the-c-language-specification/3748757#3748757。我留下前两个例子只是对我的观点的次要强化。我还添加了第三个示例,具体化了之间存在的身份转换object
and dynamic
正如埃里克的回答所指出的。
传递引用转换
假设你有两种类型,M
and N
,并且您已经定义了如下隐式转换:
public static implicit operator M(N n);
然后你可以编写这样的代码:
N n = new N();
M m = n;
现在假设您有一个包含此内容的文件using
顶部声明:
using K = M;
然后你可以在文件后面看到:
N n = new N();
K k = n;
好的,在我继续之前,我意识到这很明显you and me.但我的答案是,而且从一开始就是这样,它可能not显而易见everyone,因此指定它--同时多余的——还有一个purpose.
That purpose是:向那些摸不着头脑、查看该代码的人表明,它是合法的。一个隐式转换存在从 N 到 M,并且身份转换从 M 到 K 存在(即 M 和 K 是同一类型);所以存在从 N 到 K 的隐式转换。它不是just合乎逻辑(尽管可能be逻辑);它就在规范中。否则,人们可能会错误地认为像下面这样的东西是必要的:
K k = (M)n;
显然,事实并非如此。
传递拳击转换
或者采取类型int
. An int
可以装箱为IComparable<int>
, 正确的?所以这是合法的:
int i = 10;
IComparable<int> x = i;
现在考虑一下:
int i = 10;
IComparable<System.Int32> x = i;
Again, yes,可能是obvious献给你、我以及 90% 可能遇到过它的开发者。但对于那些没有立即看到这一点的极少数人来说:拳击转换存在于int
to IComparable<int>
, 和身份转换存在于IComparable<int>
to IComparable<System.Int32>
(i.e., IComparable<int>
and IComparable<System.Int32>
是同一类型);所以拳击转换存在于int
to IComparable<System.Int32>
.
转换涉及dynamic
type
我将借用上面的引用转换示例,并稍微调整它以说明之间的恒等关系object
and dynamic
在规范的 4.0 版本中。
假设我们有以下类型M<T>
and N
,并在某处定义了以下隐式转换:
public static implicit operator M<object>(N n);
那么以下是合法的:
N n = new N();
M<dynamic> m = n;
显然,上面的内容还少得多obvious比前两个例子。但这是一个价值百万美元的问题:上面的会still即使问题中引用的规范摘录不存在,也是合法的吗?(我将把这些摘录称为Q为简洁起见。)如果答案是肯定的,那么Q事实上是多余的。如果不是,那就不是。
我相信答案是肯定的。
考虑以下的定义身份转换,在第 6.1.1 节中定义(我在这里包含整个部分,因为它很短):
身份转换从任何类型转换为相同类型。这种转换的存在使得已经具有所需类型的实体可以说可以转换为该类型。
Because object
and dynamic
被认为是等价的,之间存在身份转换object
and dynamic
, 以及替换所有出现的相同构造类型之间dynamic
with object
. [强调我的]
(最后一部分也包含在第 4.7 节中,它定义了dynamic
type.)
现在让我们再看一下代码。我特别对这一行感兴趣:
M<dynamic> m = n;
本声明的合法性(不考虑Q--记住,正在讨论的问题是上述声明的假设合法性if Q did not存在),因为M<T>
and N
是自定义类型,取决于用户定义的隐式转换之间是否存在N
and M<dynamic>
.
存在隐式转换N
to M<object>
。根据上面引用的规范部分,之间存在身份转换M<object>
and M<dynamic>
。根据定义身份转换, M<object>
and M<dynamic>
是同一类型.
因此,就像前两个(更明显的)示例一样,我相信确实存在隐式转换N
to M<dynamic>
即使不采取Q考虑到,正如确实存在隐式转换一样N
to K
在第一个示例中,并且存在装箱转换int
to IComparable<System.Int32>
在第二个例子中。
Without Q,这不太明显(因此Q的存在);但这并不意味着它是错误的 (i.e., Q is not 必要的来定义此行为)。它只是让它变得不那么明显。
结论
我在最初的回答中说过,这是“显而易见的”解释,因为在我看来,你找错了树。您最初提出了这个挑战:
Can you give an example of two types T1, T2 such that T1 would not be implicitly convertible to T2 if it weren’t for the above-quoted paragraphs?
No one's going to meet this challenge, Timwi, because it's impossible. Take the first excerpt about reference conversions. It is saying that a type K is implicitly convertible to a type T if it is implicitly convertible to T0 and T0 is the same as T. Deconstruct this, put it back together, and you're left with an obvious tautology: K is implicitly convertible to T if it's implicitly convertible to T. Does this introduce any new implicit conversions? Of course not.
所以也许本·沃伊特的评论是正确的;也许您所询问的这些要点最好放在脚注中,而不是放在正文中。无论如何,我很清楚他们are多余的,所以从前提开始他们不能是多余的,否则他们就不会在那里就是去做一件愚蠢的事。愿意接受这样一个事实:冗余的陈述可能仍然可以阐明一个对每个人来说可能并不明显的概念,并且更容易接受这些陈述的本来面目。
多余的?是的。同义反复?是的。无意义?在my意见,没有。
*Obviously, I did not have any part in writing the C# language specification. If I did, this answer would be a lot more authoritative. As it is, it simply represents one guy's feeble attempt to make sense of a rather complex document.
原答案
我认为您(也许是故意的)忽略了这里最明显的答案。
考虑你的问题中的这两句话:
(1)最初它们看起来是多余的
(同义反复)。(2)但他们必须在那里
是有目的的,那么他们为什么在那里呢?
对我来说,这两句话放在一起的含义是同义反复的陈述没有任何意义。但仅仅因为一个陈述是从既定前提逻辑上得出的,并不会让每个人都明白这一点。换句话说,即使(1)是真的,答案是(2)可能只是:使阅读规范的任何人都清楚所描述的行为.
现在你可能会争辩说,即使有些东西不是obvious,如果它提供了冗余定义,它仍然不属于规范。对于这种潜在的反对意见,我只能说:现实一点。 (在我看来)梳理一份文件并剔除所有陈述是不太实际的,这些陈述只是陈述可以从先前陈述中推断出的事实。
If this were作为一种常见的做法,我想你会发现很多文献——不仅仅是规格,还有研究论文、文章、教科书等——会更短、更密集,也更难理解。
所以:是的,也许它们是多余的。但这并不能否定他们的目的。