为什么转换和转换操作在语法上难以区分?

Pav*_*nin 2 .net c# unboxing casting type-conversion

堆栈溢出,大约铸造盒装值几个问题:1,2.

该解决方案首先需要unbox该值,然后才将其转换为另一种类型.然而,盒装值"知道"它自己的类型,我认为没有理由不能调用转换运算符.

此外,同样的问题对参考类型有效:

void Main()
{
    object obj = new A();
    B b = (B)obj;   
}


public class A 
{
}

public class B {}
Run Code Online (Sandbox Code Playgroud)

这段代码抛出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
{
}
Run Code Online (Sandbox Code Playgroud)

它会散发出来call A.op_Explicit.

啊哈!编译器看到它A有一个运算符并调用它.但是如果B从继承中发生了什么A呢?没那么快,编译器非常聪明......它只是说:

A.explicit运算符B(A)':不允许在派生类之间进行用户定义的转换

哈!没有歧义!

但为什么在地球上他们允许两个相当不同的操作看起来相同?!是什么原因?

Eri*_*ert 10

据我所知,你的观察是我在这里做的观察:

http://ericlippert.com/2009/03/03/representation-and-identity/

C#中的强制转换运算符有两个基本用法:

(1)我的代码有一个B类型的表达式,但我碰巧有比编译器更多的信息.我声称肯定知道在运行时,类型B的这个对象实际上总是派生类型D.我将通过在表达式上插入一个强制转换来告知编译器.由于编译器可能无法验证我的声明,因此编译器可以通过在我声明的位置插入运行时检查来确保其准确性.如果我的索赔结果不准确,CLR将抛出异常.

(2)我有一个类型T的表达式,我知道它不是U型.但是,我有一个众所周知的方法将T的部分或全部值与U的"等价"值相关联.我将指示编译器通过向U添加强制转换来生成实现此操作的代码.(如果在运行时事实证明对于特定的T没有等效的U值,我们再次抛出异常.)

细心的读者会注意到这些是对立的.一个巧妙的技巧,有一个操作员意味着两个相互矛盾的事情,你不觉得吗?

所以显然你是我所谓的"细心的读者"之一,他们注意到我们有一个操作在逻辑上意味着两个相当不同的东西.这是一个很好的观察!

你的问题是"为什么会这样?" 这不是一个好问题!:-)

正如我已经指出很多在这个网站的时间,我不能回答"为什么"的问题令人满意."因为这就是规范所说的"是一个正确的答案,但并不令人满意.提问者通常在寻找的是语言设计过程的总结.

当C#语言设计团队设计功能时,辩论可以持续几个月,他们可以让十几个人讨论许多不同的提案,每个提案各有利弊,产生数百页的笔记.即使我从20世纪90年代后期的会议中获得了有关演员表演的相关信息,但我并没有这样做,但是很难用原始提问者满意的方式简明地总结出来.

而且,为了令人满意地回答这个问题,人们当然必须讨论整个历史的观点.C#旨在立即为现有的C,C++和Java程序员提供高效工作,因此它借用了这些语言的许多约定,包括转换运算符的基本机制.为了正确回答这个问题,我们还必须讨论使用C,C++和Java编译运算符的历史.这似乎是在StackOverflow的答案中预期的太多信息.

坦率地说,最可能的解释是这个决定不是不同立场的优点之间长期争论的结果.相反,语言设计团队可能会考虑如何在C,C++和Java中完成它,做出一个看起来并不太可怕的合理折衷方案,并转向其他更有趣的业务.因此,正确的答案几乎完全是历史性的; 为什么Ritchie像他为C一样设计演员?我不知道,我们不能问他.

我给你的建议是,你不再问"为什么?" 有关编程语言设计历史的问题,而是询问有关特定代码的具体技术问题,以及简短答案的问题.