铸造和转换一样吗?

时间:2008-09-27 16:57:57

标签: c# clr casting

在Jesse Liberty的Learning C#书中,他说“一种类型的物体可以转换成另一种类型的物体。这就是所谓的铸造。”

如果您调查从下面的代码生成的IL,您可以清楚地看到转换的赋值与转换的赋值没有做同样的事情。在前者中,你可以看到拳击/拆箱发生;在后者中,您可以看到对convert方法的调用。

我知道最终它可能只是一个愚蠢的语义差异 - 但是只是转换了另一个词。我并不是故意嗤之以鼻,但我对任何人的直觉都不感兴趣 - 意见不计算在这里!任何人都可以指出确认或否认铸造和转换是否相同的确定性参考?

    object x;
    int y;

    x = 4;

    y = ( int )x;

    y = Convert.ToInt32( x );

谢谢

RP

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

我不认为隐含/显性是不同的。在我发布的代码中,两种情况下的更改都是明确的。隐式转换是指向int分配short时发生的情况。

Sklivvz注意:

我想确认我怀疑Jesse Liberty的(通常是清晰明确的)语言的松散是正确的。我以为Jesse Liberty的语言有点松散。我知道转换是在对象层次结构中路由的 - 也就是说,您不能从整数转换为字符串,但是您可以从从System.Exception派生的自定义异常转换为System.Exception。

但有趣的是,当你尝试从int转换为字符串时,编译器会告诉你它无法“转换”该值。也许杰西比我想象的更正确!

12 个答案:

答案 0 :(得分:28)

绝对不是!

转换尝试通过“任何可能的方式”获取Int32。 Cast没有做那种事。使用强制转换,您告诉编译器将对象视为Int,而不进行转换。

当您(通过设计)知道对象是Int32或其他具有Int32的转换运算符的类(例如float)时,应始终使用强制转换。

Convert应与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

     

未处理的例外:

     

System.OverflowException:值为   大于Byte.MaxValue或更少   而不是Byte.MinValue   System.Convert.ToByte(Int64值)   [0x00000]在Test.Main   (System.String [] args)[0x00019] in   /home/marco/develop/test/Exceptions.cs:15

答案 1 :(得分:17)

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

对于值类型,转换将涉及真正将其转换为其他类型。例如:

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

当转换表达式取消装箱时,结果(假设它有效)通常只是框中内容的副本,具有相同的类型。但是有一些例外 - 你可以从盒装的int到enum(底层类型是int)取消装箱,反之亦然;同样,你可以从一个盒装的int解包到一个Nullable< int>。

当转换表达式从一个引用类型转到另一个引用类型并且不涉及用户定义的转换时,就对象本身而言,没有转换 - 只有引用的类型“更改“ - 这实际上只是值的方式,而不是引用本身(它将与以前相同)。例如:

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

当涉及用户定义的转换时,此通常需要返回不同的对象/值。例如,您可以为自己的类型定义转换为字符串 - 和  这肯定与您自己的对象不一样。 (当然,它可能是从您的对象引用的现有字符串。)根据我的经验,用户定义的转换通常存在于值类型而不是引用类型之间,因此这很少成为问题。

所有这些都被视为规范方面的转换 - 但它们并不都算作将对象转换为其他类型的对象。我怀疑这是一个Jesse Liberty的术语松散的例子 - 我注意到在C#3.0编程中,我刚读过这个。

这涵盖了一切吗?

答案 2 :(得分:7)

我见过的最好的解释可以在下面看到,然后是源的链接:

“......事实比这更复杂..NET提供 从A点到B点的三种方法,就像它一样。

首先,有隐式演员。这是没有的演员 要求你做任何事情而不是任务:

int i = 5;
double d = i;

这些也称为“扩展转换”,.NET允许您这样做 没有任何演员操作员执行它们,因为你永远不会失去任何 执行此操作的信息:double的有效值的可能范围 包含int的有效值范围,然后包含一些有效值 你永远不会做这个任务,然后发现你的 运行时从你的int值减去几位数的恐怖。对于 引用类型,隐式转换背后的规则是强制转换 永远不会抛出InvalidCastException:编译器很清楚 演员表总是有​​效的。

您可以为自己的类型创建新的隐式转换运算符(哪些 意味着你可以制作破坏所有规则的隐式强制转换,如果 你这是愚蠢的)。基本的经验法则是隐含的 演员阵容永远不会包含丢失信息的可能性 过渡。

请注意,基础表示中发生了更改 转换:double与int完全不同。

第二种转换是显式转换。一个明确的演员是 在有可能丢失信息的地方要求,或 演员有可能无效并因此投掷 InvalidCastException:

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

在这里你显然会失去信息:我将在1之后 施展,所以0.5迷路了。这也被称为“缩小” 转换,编译器要求您包含显式转换 (int)表示是,你知道信息可能会丢失,但是 你不在乎。

类似地,对于引用类型,编译器需要显式转换 演员表在运行时可能无效的情况,作为信号 是的,你知道存在风险,但你知道你在做什么。

第三种转换是涉及这种彻底改变的转变 在表示中,设计师甚至没有提供明确的 cast:它们会让你调用一个方法来进行转换:

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

请注意,这里绝对不需要方法调用。 隐式和显式转换也是方法调用(这就是你的方法 你自己)。设计师可以很容易地创建一个明确的 将字符串转换为int的转换运算符。要求 你称一种方法是一种风格选择而不是根本 语言的要求。

风格推理是这样的:String-to-int是一个 复杂的转换,有很多机会进行 可怕的错误:

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

因此,方法调用为您提供了阅读文档和广泛的文档 暗示这不仅仅是一个快速演员。

在设计自己的类型(特别是您自己的值类型)时,您 可能决定创建转换运算符和转换函数。线条 划分“隐式演员”,“显性演员”和“转换函数” 领土有点模糊,所以不同的人可能会有所不同 决定什么应该是什么。试着记住 信息丢失,异常和无效数据的可能性,以及 这应该可以帮助你做出决定。“

  • Bruce Wood,2005年11月16日

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

答案 3 :(得分:2)

投射涉及参考

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中。这是因为它们都是同一个实例的引用(不同类型)。

向上铸造是安全的。如果程序员在类型中犯了错误,则向下转换会产生运行时错误。安全的降级超出了这个答案的范围。

转换涉及实例

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

myList用于生成myArray。这是一种非破坏性的转换(myList在此操作后完美运行)。另请注意,针对myList的操作(例如添加元素)不会反映在myArray中。这是因为它们是完全独立的实例。

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

在C#中使用强制语法的操作是actually conversions

答案 4 :(得分:1)

除了语义,快速测试显示他们不等同!
他们以不同的方式完成任务(或者,他们执行不同的任务)。

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个案例。

答案 5 :(得分:0)

强制转换告诉编译器/交互操作者该对象实际上属于该类型(或者具有该类型的基本类型/接口)。与转换相比,这是一个非常快速的事情,它不再是编译器/交互操作员,而是一个实现解析字符串并进行数学转换为数字的函数。

答案 6 :(得分:0)

转换始终意味着更改对象的数据类型。这可以通过例如将浮点值转换为整数值或通过重新解释位来完成。它通常是语言支持的(读取:编译器支持的)操作。

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

答案 7 :(得分:0)

以语言/框架无关的方式,从一种类型或类别转换为另一种类型或类别称为强制。对于.NET也是如此,正如您的前四行所示:

object x;
int y;

x = 4;

y = ( int )x;

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

y = CInt(x)

或者,对于更复杂的类型:

y = CType(x, newtype)

'C'显然是'cast'的缩写。

.NET也有Convert()函数。这不是一个内置的语言功能(不同于上面两个),而是一个框架。当你使用一种不一定与.NET一起使用的语言时,这会变得更加清晰:它们仍然很可能有自己的投射方法,但它是添加Convert()的.NET。

正如马特所说,行为上的差异是Convert()更明确。您只是告诉编译器将y视为等效于x的整数,而不是仅仅告诉它以适合整数类的方式改变x然后将结果分配给y

在您的特定情况下,强制转换执行所谓的“取消装箱”,而Convert()实际上将获取整数值。结果看起来是一样的,但有更微妙的差异explained by Keith

答案 8 :(得分:0)

根据 MCTS Self-Paced Training Kit(考试70-536)第1章第4课第55页标题为“显式转换方法”的表1-7:Microsoft®.NETFramework 2.0-应用程序发展基金会,它们之间肯定存在差异。

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

(类型)强制转换运算符是一种 C#特定的语言功能,可转换“定义转换运算符的类型之间。”

此外,在实施自定义转化时,建议不同

根据上述课程中第56-57页的标题为如何在自定义类型中实现转换的部分,转换运算符(强制转换)用于简化数字类型之间的转换,而Convert()支持特定于文化的转换

  

您选择哪种技术取决于您要执行的转换类型:

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

  •   
  • 实施 System.IConvertible 以启用转换功能   System.Convert。使用此技术启用特定于文化的转换。

  •   
  • ...

  •   

现在应该更清楚的是,由于强制转换运算符是与IConvertible接口分开实现的,因此Convert()不一定只是另一个用于强制转换的名称。 (但我可以设想一个实现可以引用另一个实现以确保一致性。)

答案 9 :(得分:-1)

不要忘记转换和转换变量的其他方法:as,Parse,TryParse 以及兼容数据类型之间的隐式转换。

该网站对大多数方法的输出有很好的样本: C# Boxing and Unboxing

所以给出了这些样本变量:

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

基本上,您可以在两种兼容类型之间进行隐式转换:

l = i;

使用取消装箱或关键字进行明确投射:

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

使用System.Convert:

中的方法进行显式转换
i = System.Convert.ToInt32(s);

使用定义数据类型中的方法进行显式转换:

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

使用变量实例中的方法进行显式转换:

s = i.ToString();

我认为投射只是在两种兼容类型之间进行分配的一种方式。

转换是指您需要将值从一种不兼容的类型显式复制到另一种类型,并且您不能信任evil coercion

MSDN上的一些好消息:Casting and Type Conversions

答案 10 :(得分:-2)

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

然而,

转换将执行将一种类型转换为另一种类型的操作。

举个例子:

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

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

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

答案 11 :(得分:-4)

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