类型转换的不同方式。有什么区别?

4
我将尝试区分类型转换的不同方法。
例如: 方法1
public byte fun()
{
   object value=1;
   return (byte)value; // this gives me error
}

Method 2

public byte fun()
{
   object value=1;
   return byte.Parse(value.ToString()); // this runs 
}

方法三

public byte fun()
{
   object value=1;
   return Convert.ToByte(value); // this runs
}

这三者有什么区别?它们在内部是如何工作的?这里的值类型和引用类型是什么?哪个函数可以将值类型转换为引用类型,反之亦然。

编辑2

当我写下这行代码时,“1”默认会被视为int32、byte或其他什么数据类型?

object value=1;


此外还有 bool byte.TryParse(string, out double value) - AxelEckenberger
@Obalix:应该是byte。尝试解析(string,out byte value)。 - Reed Copsey
3个回答

8

这里有很多问题。

方法1失败是因为你不能在单个操作中进行拆箱和强制转换。你正在将"value"设置为一个装箱的整数。当您尝试进行强制转换时,您正在将整数解包并尝试在单个操作中将其转换为字节,这会失败。顺便说一句,这样做是可以成功的:

return (byte)( (int)value) ); // Unbox, then cast, in two operations

方法2的原理是将整数转换为字符串,然后使用byte.Parse将其转换为字节。这非常昂贵,因为它需要进行字符串转换。
方法3的原理是看到value中的对象是IConvertible(int),并使用适当的转换操作将其转换为字节。在这种情况下,这可能是一种更有效的方法。由于"value"存储一个int,并且int支持IConvertible,Convert.ToByte基本上会执行空检查,然后调用Convert.ToByte(int),这非常快速(它执行边界检查和直接转换)。
我建议阅读Eric Lippert的博客文章Representation and Identity。它详细介绍了类型转换,并解释了为什么方法1失败...

1
// This is a direct cast. It expects that the object
// in question is already allocated as the data type
// indicated in the cast
(byte)value;

// This is a direct code conversion. It takes the argument
// and runs through code to create a new variable of the
// type byte. You'll notice if you include this in different
// code that value will still be an object but your new
// data will be a byte type
byte.Parse(value.ToString());

// This will convert any object similarly to the byte.Parse.
// It is not as fast because it does not have a definitely
// typed parameter (as parse has string). So it must go 
// through a couple of extra steps to guarantee the conversion
// is smooth.
Convert.ToByte(value);

直接转换始终是最快的。它假设类型已经确定和分配,因此它只需要在内存中切换其引用类型。转换方法是代码转换,因此它们需要更多时间。我不知道基准测试,但解析稍微快一些,因为它处理特定的输入和输出(字符串->字节)。转换是转换方法中最慢的,因为它缺乏同样的特定性。


他的第一种方法并不是直接转换,而是一个拆箱+转换,这会失败。 - Reed Copsey
另外,Convert更快,因为它可以直接使用int.ToByte(来自IConvertible.ToByte)。 - Reed Copsey
@Reed Copsey:如果它最初是作为一个字节实例化的,那么它就是拆箱。但它不是,它开始分配为一个对象。为了使其“拆箱”,必须先将其从字节装箱为对象。在这种情况下,它是直接转换,这就是为什么它失败的原因。请参见:http://msdn.microsoft.com/en-us/library/b95fkada(VS.80).aspx和http://msdn.microsoft.com/en-us/library/ms173105(VS.80).aspx - Joel Etherton
不,它被实例化为Int32,因为这是默认的整数字面量。这个Int32被装箱成一个对象"value"。当你尝试将其转换为byte时,它会先进行拆箱操作,然后尝试一次性进行类型转换,这会导致运行时错误(InvalidCastException)。参见:http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx - Reed Copsey

0

这是我的尝试:

方法1

这是一种类型转换,即值必须是可以隐式或显式转换为字节的类型。此外,值不能超出字节的范围。

调用失败,因为编译器没有任何信息可以从中进行强制转换的对象类型,因此无法执行隐式或显式转换。做

int obj = 1;
byte b = (byte) obj; 

或者

byte b = (byte) (int) obj;

行。第二个选项使用显式拆箱(因此提供所需的信息),如Reed Copsey的评论和帖子中所述。Reed Copsey的评论提供的链接详细解释了这一点。

对于自定义对象转换,使用隐式和显式转换是在类上定义的静态方法的运算符。对于object,不存在隐式或显式操作(请参阅链接以了解原因),而对于int,存在这些操作。

方法2

在这里,您正在解析一个字符串,该字符串的值必须是在字节范围内的数字。在这里,您还可以使用TryParse,它允许您检查转换是否成功。

方法3

使用Convert类的类型转换。这是最灵活的方法,支持大多数常见类型。在这里,值必须可转换为数字,并且值必须在字节范围内。Convert类使用IConvertible在不同类型之间进行转换,因此具有可扩展性。


1
你的“方法1”解释是不正确的。这是关于拆箱的特定限制,即:类型T的拆箱只能直接拆箱为T。请参见:http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx - Reed Copsey
不确定那个链接是否与我的陈述相矛盾...我猜你想到的是 int jjj = (int) (short) ooo; 这个语句。按照我的理解,它等同于 short s = (short) ooo; int i = (int) short;。这种行为与我所写的一致。 - AxelEckenberger
这不是编译器“没有关于应该转换成什么类型对象的信息”的问题,而是当您进行取消装箱时类型不同,并且您无法在一次操作中进行取消装箱+转换。 - Reed Copsey
@Reed Copsey:我刚刚阅读了您发布的文档,明白了您的意思。因此,我编辑了我的答案,使其更加精确。 - AxelEckenberger
此外 - 强制类型转换并不是一个运算符,它是语言规范的一部分... - Reed Copsey
从未说过其他的...虽然它使用了隐式和显式类型转换,但至少对于非内置类型而言。因此,我认为内置类型也有类似的概念。 - AxelEckenberger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接