Stack Overflow 有几个关于转换盒装值的问题:1 , 2 .
该解决方案首先需要unbox
值,然后才将其转换为另一种类型。然而,装箱值“知道”它自己的类型,我看不出有什么理由不能调用转换运算符。
此外,同样的问题也适用于引用类型:
void Main()
{
object obj = new A();
B b = (B)obj;
}
public class A
{
}
public class B {}
此代码抛出 InvalidCastException
。所以这不是值与引用类型的问题;这就是编译器的行为方式。
对于上面的代码,它发出castclass B
,对于代码
void Main()
{
A obj = new A();
B b = (B)obj;
}
public class A
{
public static explicit operator B(A obj)
{
return new B();
}
}
public class B
{
}
它发出 call A.op_Explicit
。
啊哈!这里编译器看到 A
有一个运算符并调用它。但是如果 B
继承自 A
会发生什么?没那么快,编译器很聪明……它只是说:
A.explicit operator B(A)': user-defined conversions to or from a derived class are not allowed
哈!没有歧义!
但到底为什么他们允许两种截然不同的操作看起来一样?!原因是什么?
最佳答案
据我所知,您的观察就是我在这里所做的观察:
http://ericlippert.com/2009/03/03/representation-and-identity/
There are two basic usages of the cast operator in C#:
(1) My code has an expression of type B, but I happen to have more information than the compiler does. I claim to know for certain that at runtime, this object of type B will actually always be of derived type D. I will inform the compiler of this claim by inserting a cast to D on the expression. Since the compiler probably cannot verify my claim, the compiler might ensure its veracity by inserting a run-time check at the point where I make the claim. If my claim turns out to be inaccurate, the CLR will throw an exception.
(2) I have an expression of some type T which I know for certain is not of type U. However, I have a well-known way of associating some or all values of T with an “equivalent” value of U. I will instruct the compiler to generate code that implements this operation by inserting a cast to U. (And if at runtime there turns out to be no equivalent value of U for the particular T I’ve got, again we throw an exception.)
The attentive reader will have noticed that these are opposites. A neat trick, to have an operator which means two contradictory things, don’t you think?
显然,您是我召集的“细心的读者”之一,他们注意到我们有一个操作在逻辑上意味着两个截然不同的事情。这是一个很好的观察!
您的问题是“为什么会这样?”这不是一个好问题! :-)
正如我在本网站上多次指出的那样,我无法满意地回答“为什么”问题。 “因为那是规范所说的”是一个正确的答案,但并不令人满意。实际上,提问者通常寻找的是语言设计过程的摘要。
当 C# 语言设计团队设计功能时,争论可能会持续几个月,他们可能会涉及十几个人讨论许多不同的提案,每个提案都有自己的优缺点,从而产生数百页的笔记。即使我从 1990 年代后期的 session 上获得了有关类型转换操作的相关信息(我没有),似乎也很难以一种让最初的提问者满意的方式对其进行简洁的总结。
而且,要圆满回答这个问题,当然要从整个历史的角度来讨论。 C# 旨在让现有的 C、C++ 和 Java 程序员立即高效工作,因此它借鉴了这些语言的许多约定,包括转换运算符的基 native 制。为了正确回答这个问题,我们还必须讨论 C、C++ 和 Java 中转换运算符的历史。在 StackOverflow 上的答案中,这似乎包含太多信息。
坦率地说,最可能的解释是这个决定不是不同立场的长处辩论的结果。相反,语言设计团队可能考虑了如何在 C、C++ 和 Java 中完成,做出了一个看起来不太糟糕的合理折衷,然后转向其他更有趣的业务。因此,一个正确的答案几乎完全是历史性的;为什么 Ritchie 像他为 C 所做的那样设计转换运算符?我不知道,我们也不能问他。
我的建议是不要再问“为什么?”有关编程语言设计历史的问题,而是询问有关特定代码的特定技术问题,这些问题的答案很简短。
关于c# - 为什么转换和转换操作在语法上无法区分?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29036785/