问题

我通常会尽量避免使用类型,因为我的印象是它的编码习惯很差,可能会导致性能下降。

但如果有人让我解释为什么会这样,我可能会把它们看成是头灯中的鹿。

那么为什么/何时铸造不好?

它是一般的java,c#,c还是每个不同的运行时环境都按照它自己的条件处理它?

任何语言的细节都是受欢迎的,例如为什么它在c中不好?


#1 热门回答(128 赞)

你用三种语言对它进行了标记,三者之间的答案非常不同。对C的讨论或多或少意味着对C演员的讨论,并给出(或多或少)第四个答案。

因为它是你没有明确提到的那个,所以我将从C开头.C演员阵容有很多问题。一个是他们可以做许多不同的事情。在某些情况下,演员只会告诉编译器(实质上):"闭嘴,我知道我在做什么" - 即,它确保即使你做了可能导致问题的转换,编译器不会警告你这些潜在的问题。例如,char a=(char)123456;。定义此实现的确切结果(取决于char的大小和签名),除了在相当奇怪的情况下,可能没有用。 C转换也有所不同,它们是否仅在编译时发生(即,你只是告诉编译器如何解释/处理某些数据)或在运行时发生的事情(例如,实际从double转换为长)。

C试图通过添加一些"新的"强制转换操作符来至少在某种程度上处理它,每个操作符仅限于C强制转换的一部分功能。这使得(例如)意外地进行你真正不想要的转换变得更加困难 - 如果你只是想要抛弃一个对象的constness,你可以使用const_cast,并确保它可以影响的对象是对象是否是constvolatile,或不。相反,astatic_cast不允许影响对象是否为constvolatile。简而言之,你拥有大多数相同类型的功能,但它们被分类,因此一个转换通常只能进行一种转换,其中单个C样式转换可以在一次操作中执行两次或三次转换。主要的例外是你至少在某些情况下使用adynamic_cast代替astatic_cast,尽管被写为adynamic_cast,但它最终会以astatic_cast结尾。例如,你可以使用dynamic_cast遍历或缩小类层次结构 - 但是层次结构的"向上"始终是安全的,因此它可以静态完成,而层次结构中的"向下"不一定是安全的,因此它已完成动态。

Java和C#彼此更相似。特别是,对于它们两者而言(实际上?)始终是运行时操作。就C转换运算符而言,它通常最接近adynamic_cast的条件 - 即,当你尝试将对象转换为某个目标类型时,编译器会插入运行时检查以查看是否允许该转换,如果不是,则抛出异常。确切的细节(例如,用于"糟糕演员"异常的名称)各不相同,但基本原则仍然大致相似(但是,如果内存服务,Java确实会将强制转换应用于少数非对象类型,如int,这更接近于C演员阵容 - 但这些类型的使用很少,1)我不记得这一点,2)即使它是真的,无论如何都无关紧要)。

更普遍地看待事情,情况非常简单(至少是IMO):演员(显然足够)意味着你正在将某种东西从一种类型转换为另一种类型。当/如果你这样做,它提出了一个问题"为什么?"如果你真的想要特定类型的东西,为什么不把它定义为该类型开始?这并不是说进行这种转换的原因是什么,但是只要它发生,它应该提示你是否可以重新设计代码以便在整个过程中使用正确的类型。即使看似无害的转换(例如,在整数和浮点之间)也应该比常见的更加密切地进行检查。尽管它们具有相似性,但整数应该用于"计数"类型的事物和"测量"类型事物的浮点数。忽视这种区别是导致一些疯狂的陈述,如"普通美国家庭有1.8个孩子"。即使我们都能看到这种情况如何发生,但事实是,他们有1.8个孩子。他们可能有1或者他们可能有2或者他们可能有更多 - 但从来没有1.8。


#2 热门回答(42 赞)

这里有很多好的答案。这是我看待它的方式(从C#角度来看)。

铸造通常意味着两件事之一:

  • 我知道这个表达式的运行时类型,但编译器不知道它。编译器,我告诉你,在运行时,对应于这个表达式的对象实际上就属于这种类型。截至目前,你知道此表达式将被视为此类型。生成假定对象将具有给定类型的代码,或者如果我错了则抛出异常。
  • 编译器和开发人员都知道表达式的运行时类型。还有另一个与此表达式在运行时将具有的值相关联的值的值。生成从给定类型的值生成所需类型值的代码;如果你不能这样做,那么抛出异常。

请注意那些isopposites。有两种演员阵容!有一些转换,你在编译器中给出了关于实际的信息 - 嘿,类型对象的这个东西实际上是Customer类型 - 并且有一些转换器,你告诉编译器执行从一种类型到另一种类型的映射 - 嘿,我需要int这对应于这个双倍。

两种演员都是红旗。第一种类型的演员提出了一个问题"为什么开发人员知道编译器不知道的东西到底是什么?"如果你处于这种情况,那么更好的做法通常是更改程序,以便编译器能够处理现实。那你就不需要演员;分析在编译时完成。

第二种类型的演员提出了一个问题"为什么不首先在目标数据类型中进行操作?"如果你需要一个int的结果,那你为什么要先拿一个双?你不应该持一个int吗?

还有一些额外的想法:
http://blogs.msdn.com/b/ericlippert/archive/tags/cast+operator/


#3 热门回答(34 赞)

转换错误始终报告为java中的运行时错误。使用泛型或模板将这些错误转换为编译时错误,使你在出错时更容易检测到错误。

正如我上面所说。这并不是说所有的铸造都很糟糕。但如果有可能避免它,最好这样做。


原文链接