c# - 为什么转换和转换操作在语法上无法区分?

标签 c# .net casting type-conversion unboxing

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/

相关文章:

c# - 如何在 C# 中为 COM STA 线程发送消息?

c# - 在另一个 Web API 中管理 Web API JWT token 的最佳实践

c# - 来自 DataVisualization.Charting.Axis.GetLinearPosition() 的 NullReferenceException

c# - 我应该将什么 'length' 参数传递给 SqlDataReader.GetBytes()

java - 需要在 Byte 和 Short 中进行转换

C# 加入线程

c# - VS Express和专业有冲突吗?

c# - 在 C# 中使用字符串作为名称创建对象

c# - 在 C# 中,可以将 Char 转换为 Int32 产生负值吗?

actionscript-3 - 如何在 Actionscript 3 中为我自己的类实现转换?