是铸造一样东西转换?

在Jesse Liberty的Learning C#书中,他说:“一种types的对象可以被转换成另一种types的对象,这就是所谓的”铸造“。

如果您调查下面的代码生成的IL,您可以清楚地看到,铸造的分配与转换后的分配没有相同的作用。 在前者,你可以看到拳击/拆箱的发生; 在后者中,您可以看到对转换方法的调用。

我最终知道它可能只是一个愚蠢的语义上的差异 – 但是转换只是换一个词。 我不是故意的,但是我对这个人的直觉并不感兴趣 – 意见不在这里! 任何人都可以指出一个明确的参考,确认或否认,如果铸造和转换是同一件事情?

object x; int y; x = 4; y = ( int )x; y = Convert.ToInt32( x ); 

谢谢

RP

注意在Matt关于显性/隐性的评论之后添加的:

我不认为隐含/显式是差别。 在我发布的代码中,这两种情况都是明确的。 隐式转换是将short指定给int时发生的。

请注意Sklivvz:

我希望得到证实,我怀疑Jesse Liberty(通常是清晰明了的)语言的松散是正确的。 我认为杰西·利伯蒂(Jesse Liberty)的语言有点松散。 我明白,铸造路由在对象层次结构 – 即,你不能从一个整数转换为一个string,但你可以从自定义exception派生从System.Exception转换为System.Exception。

不过有趣的是,当你试图从一个int转换为一个string时,编译器告诉你它不能“转换”这个值。 也许杰西比我想的更正确!

简单的答案是:这取决于。

对于价值types,铸造将涉及真正将其转换为不同的types。 例如:

 float f = 1.5f; int i = (int) f; // Conversion 

当转换expression式取消装箱时,结果(假设它起作用) 通常只是框中的内容的副本,具有相同的types。 然而,也有例外 – 你可以从盒装int到一个enum(具有int的基本types),反之亦然; 同样,你可以从一个盒装int到一个Nullable <int>。

当转换expression式从一个引用types到另一个引用types,并且不涉及用户定义的转换时,就对象本身而言,不存在转换 – 只有引用的types“改变” – 并且这仅仅是价值被认为是,而不是参考本身(这将是以前相同的位)。 例如:

 object o = "hello"; string x = (string) o; // No data is "converted"; x and o refer to the same object 

当涉及用户定义的转换时, 通常需要返回不同的对象/值。 例如,你可以为自己的types定义一个string转换 – 这肯定不会和你自己的对象有相同的数据。 (当然,这可能是一个现有的从你的对象引用的string。)根据我的经验,用户定义的转换通常存在于值types之间,而不是引用types,所以这个问题很less。

所有这些在规范方面都算作转换 – 但它们并不都是将对象转换为不同types的对象 。 我怀疑这是Jesse Liberty松散的术语 – 我注意到,在我正在阅读的C#3.0编程。

这是否涵盖一切?

绝对不!

转换试图让你通过“任何方式可能”Int32。 演员什么都不做。 通过强制转换,您正在告诉编译器将对象视为Int,而不进行转换。

当你(通过devise)知道该对象是一个Int32或者另一个具有一个到Int32的铸造操作符的类(例如float)时,你应该总是使用cast。

转换应该与String或其他类一起使用。

尝试这个

 static void Main(string[] args) { long l = long.MaxValue; Console.WriteLine(l); byte b = (byte) l; Console.WriteLine(b); b = Convert.ToByte(l); Console.WriteLine(b); } 

结果:

9223372036854775807

255

未处理的exception:

System.OverflowException:值大于Byte.MaxValue或小于Byte.MinValue在System.Convert.ToByte(Int64值)[0x00000]在Test.Main(System.String []参数)[0x00019]在/ home / marco /develop/test/Exceptions.cs:15

我已经看到的最好的解释可以在下面看到,其次是一个链接到源:

“…实际情况比这更复杂一点,.NET提供了三种从A点到B点的方法。

首先是隐含的演员。 这是不需要你做任何事情的转换:

 int i = 5; double d = i; 

这些也被称为“扩展转换”,.NET允许你在没有任何转换运算符的情况下执行它们,因为你永远不会丢失任何信息:double的有效值的可能范围包含int的有效值的范围,然后有些,所以你永远不会做这个任务,然后发现你的恐惧,运行时从你的int值下降了几个数字。 对于引用types,隐式转换背后的规则是转换绝不会抛出InvalidCastException:编译器清楚转换总是有效的。

你可以为自己的types创build新的隐式转换运算符(这意味着如果你愚蠢的话,你可以做隐式转换来打破所有的规则)。 基本的经验法则是,隐式的转换决不能包含在转换中丢失信息的可能性。

请注意,底层表示在此转换中确实发生了变化:double表示与int完全不同。

第二种转换是明确的转换。 只要存在丢失信息的可能性,就要求进行明确的转换,否则转换可能无效,从而引发InvalidCastException:

 double d = 1.5; int i = (int)d; 

在这里,你显然会失去信息:在演员阵容之后,我会成为1,所以0.5会丢失。 这也被称为“缩小”转换,编译器要求你包含一个明确的cast(int)来表明是的,你知道信息可能会丢失,但是你不在乎。

类似地,对于引用types,编译器在运行时可能无效的情况下需要显式强制转换,作为是的信号,您知道存在风险,但是您知道自己在做什么。

第三种types的转换是一种涉及如此激烈的表示变化,即devise者甚至没有提供明确的转换:他们让你调用一个方法来完成转换:

 string s = "15"; int i = Convert.ToInt32(s); 

请注意,这里绝对不需要调用方法。 隐式和显式强制转换也是方法调用(这就是你自己做的)。 devise者可以很容易地创build一个显式的转换操作符,将string转换为int。 您调用方法的要求是一种风格select,而不是该语言的基本要求。

风格推理是这样的:string到int是一个复杂的转换,有很多的机会,可怕的错误的事情:

 string s = "The quick brown fox"; int i = Convert.ToInt32(s); 

因此,方法调用可以让你阅读文档,并提供一个广泛的暗示,这不仅仅是一个快速的演员。

当devise你自己的types(特别是你自己的值types)时,你可以决定创build演员操作和转换function。 “隐式投射”,“显式投射”和“转换function”区域的界线有点模糊,所以不同的人可能会做出不同的决定。 只要记住信息丢失,以及潜在的例外和无效的数据,这应该帮助你决定。“

  • 布鲁斯·伍德,2005年11月16日

http://bytes.com/forum/post1068532-4.html

铸造涉及参考

 List<int> myList = new List<int>(); //up-cast IEnumerable<int> myEnumerable = (IEnumerable<int>) myList; //down-cast List<int> myOtherList = (List<int>) myEnumerable; 

注意对myList的操作,例如添加元素,反映在myEnumerable和myOtherList中。 这是因为它们都是对同一个实例的不同types的引用。

上铸是安全的。 如果程序员在types上犯了错误,那么向下转换会产生运行时错误。 安全的下载超出了这个答案的范围。

转换涉及实例

 List<int> myList = new List<int>(); int[] myArray = myList.ToArray(); 

myList用于生成myArray。 这是一个非破坏性的转换(myList在这个操作之后工作得很好)。 另外请注意,针对myList的操作(如添加元素)不会反映在myArray中。 这是因为他们完全是单独的事例。

 decimal w = 1.1m; int x = (int)w; 

在C#中有使用转换语法的操作。

除了语义学之外,一个快速testing表明它们不是等价的!
他们以不同的方式执行任务(或者也许他们执行不同的任务)。

 x=-2.5 (int)x=-2 Convert.ToInt32(x)=-2 x=-1.5 (int)x=-1 Convert.ToInt32(x)=-2 x=-0.5 (int)x= 0 Convert.ToInt32(x)= 0 x= 0.5 (int)x= 0 Convert.ToInt32(x)= 0 x= 1.5 (int)x= 1 Convert.ToInt32(x)= 2 x= 2.5 (int)x= 2 Convert.ToInt32(x)= 2 

注意x=-1.5x=1.5情况。

强制转换告诉编译器/插入器,实际上该对象是这种types的(或者具有该types的基types/接口)。 与转换器相比,这是一个相当快的事情,它不再是编译器/ interperter做这个工作,而是一个函数,可以parsing一个string,并将math转换为数字。

铸造总是意味着改变一个物体的数据types。 这可以通过例如将浮点值转换为整数值或通过重新解释这些位来完成。 它通常是一种语言支持(阅读:编译器支持)的操作。

术语“转换”有时用于转换,但通常由某个库或自己的代码完成,并不一定与转换相同。 例如,如果您有一个英制重量值并将其转换为公制重量,则它可以保持相同的数据types(比如float),但是会变成不同的数字。 另一个典型的例子是从度数转换为弧度。

以语言/框架无关的说话方式,从一种types或类别转换为另一种types被称为“ 铸造” 。 对于.NET也是如此,因为前四行显示:

 object x; int y; x = 4; y = ( int )x; 

C和C类语言(如C#)使用(newtype)somevar语法来进行强制转换。 在VB.NET中,例如,有明确的内置函数。 最后一行会写成:

 y = CInt(x) 

或者,对于更复杂的types:

 y = CType(x, newtype) 

“C”明显是“cast”的缩写。

但.NET也有Convert()函数。 这不是一个内置的语言function(不像以上两个),而是框架之一。 当你使用一种不一定和.NET一起使用的语言时,这种情况会变得更加清晰:他们仍然很可能有自己的铸造手段,但是它增加了Convert()

正如马特所说,行为的不同在于Convert()更加明确。 而不是仅仅告诉编译器把y当作x一个整数等价,你明确地告诉它把x改成适合整数类的方式, 然后把结果赋给y

在你的具体情况下,转换执行所谓的“拆箱”,而Convert()实际上将获得整数值。 结果看起来是一样的,但Keith更好地解释了一些细微的差异。

根据MCTS Self-Paced Training Kit(考试70-536)第1章第4课中的第55页上的表1-7标题为“显式转换的方法” :Microsoft®.NET Framework 2.0-应用程序开发基础他们之间的差异。

System.Convert是语言无关的,并转换为“实现System.IConvertible接口的types之间”。

(types) 强制转换运算符是一种特定C#的语言function,可以转换“定义转换运算符的types之间”。

而且,在实现自定义转换时, build议会有所不同

转换操作符(转换)是为了简化数字types之间的转换,而Convert()则可以转换特定于文化的转换 。有关如何在自定义types中实现转换的章节,请参见上文中的第56-57页。

您select哪种技术取决于您要执行的转换types:

  • 定义转换运算符以简化数字types之间的缩小和扩大转换。

  • 实现System.IConvertible通过System.Convert启用转换。 使用这种技术来启用文化特定的转换。

现在应该更清楚一点了,既然转换操作符与IConvertible接口分开实现,那么Convert()不一定只是另一个名称。 (但是我可以设想一个实现可以引用另一个来确保一致性)。

不要忘记铸造和转换variables的其他方法:as,Parse,TryParse以及兼容数据types之间的隐式转换。

这个网站有一个很好的例子,大部分的方法输出: C#拳击和拆箱

所以给这些样本variables:

 int i = 3, x; long l; string s = "5"; 

基本上你可以在两个兼容的types之间进行隐式转换:

 l = i; 

使用拆箱或as关键字明确投射:

 s = (string)i; //or s = i as string; 

使用System.Convert中的方法显式转换:

 i = System.Convert.ToInt32(s); 

使用已定义数据types的方法进行显式转换:

 i = int.Parse(s); i = int.TryParse(s, x); 

使用来自variables实例的方法的显式转换:

 s = i.ToString(); 

我认为, 铸造只是一种在两种兼容types之间进行分配的方式。

如果你需要显式地将一个值从一个不兼容的types复制到另一个,你就不能相信邪恶的强制 。

还有一些关于MSDN的很好的信息: Casting和Type转换

Casting本质上只是告诉运行时“假装”对象是新的types。 它不以任何方式实际转换或更改对象。

然而,转换将执行将一种types转换为另一种types的操作。

举个例子:

 char caster = '5'; Console.WriteLine((int)caster); 

这些语句的输出将是53,因为所有运行时确实是看位模式,并将其视为一个int。 最终得到的是字符5的ascii值,而不是数字5。

如果你使用Convert.ToInt32(caster),你会得到5,因为它实际上读取string并正确地修改它。 (本质上它知道ASCII值53实际上是整数值5)

不同之处在于转换是隐式的还是显式的。 第一个是一个强制转换,第二个是对一个转换函数的更明确的调用。 他们可能会用不同的方式来做同样的事情。