Convert.ToInt16和(Int16)之间的区别是什么

本文关键字:之间 区别 是什么 Int16 ToInt16 Convert | 更新日期: 2023-09-27 18:06:27

我有以下一段代码

try
{
  object s = new object();
  s = 10;
  Console.WriteLine("{0}", Convert.ToInt16(s));
  Console.WriteLine("{0}", (Int16)s);
}
catch (InvalidCastException ex)
{
  Console.WriteLine(ex.Message);
  Console.ReadLine();
}

在此基础上,我有很多问题
1( 是Convert.ToInt16((和(Int16(都是取消装箱操作
2( 如果两者都与取消装箱有关,那么为什么它们不同。因为当符合Console.WriteLine("{0}", (Int16)s);行时,上面的代码显示以下错误
错误:
指定的强制转换无效
3( 正如我所知,(Int16)是传统铸造,Convert.ToInt16()是类型安全转换。但是,是什么让这里有所不同呢?也许这是个愚蠢的问题,但我很困惑。请帮我澄清一下,并纠正我的错误。

Convert.ToInt16和(Int16)之间的区别是什么

数字文字10被视为整数,更具体地说是Int32。尽管您将变量键入为object,但隐藏在中,它仍然是整数。只能直接将值类型取消框为其相同类型,或取消框为该类型的可为null的版本。

例如,此代码:

int i = 10;
object o = i;
short j = (short)o; 

不会执行,因为i的原始值不是短值,而是整数。您必须先取消装箱为integer,然后才能强制转换为short。

short j = (short)(int)o;

Convert.ToInt16回避了这个问题,它的实现方式是一个实现细节。但是,该方法有多个重载,可以接受包括字符串在内的多种类型,因此它与使用直接转换的代码等价。


编辑:我注意到我在这里混合了术语,所以对于一个新手C#阅读器来说,shortInt16的名称对于16位整数是可互换的,intInt32的名称对于32位整数也是可互换的。在C#中,shortint分别是.NET类型Int16Int32的别名。

您的代码违反了C#语言规则。C#语言规范第4.3.2章说:

若要在运行时成功取消装箱转换为给定的不可为Null的值类型,源操作数的值必须是对该不可为null的值类型的装箱值的引用。如果源操作数为null,则引发System.NullReferenceException。如果源操作数是对不兼容对象的引用,则会引发System.InvalidCastException。

"不兼容对象"可能不是最清晰的语言,在谈论值类型时并没有多大帮助,但它表明你只能取消装箱到int。不允许转换为Int16(又称缩写(。这个规则不是任意的,它允许抖动生成非常有效的代码。它不必考虑转换,因此可以直接访问装箱对象中的位。这可以在没有任何辅助方法的情况下完全内联完成,它需要十几条机器代码指令。这在.NET1.x中非常重要,当时还没有泛型。因此,像ArrayList这样的集合类必须存储装箱的值。要将它们从集合中取出,需要取消装箱。

是的,Convert类就是解决方法。它利用了实现IConvertable接口的值类型。因此,它最终将调用Int32.ToInt16((方法。先将其取消装箱为int,然后强制转换为Int16。效率不高,但没有卡博姆。

在问题行中,您试图将非Int16(可能是Int32?(的内容强制转换为Int16类型。如果你把分配改成这个,我敢打赌它会起作用(视频(:

object s, s2;
s = Convert.ToInt16(10);
s2 = 10;
Console.WriteLine("Types: {0} and {1}", s.GetType(), s2.GetType());
Console.WriteLine("s as Int16 (works): {0}", (Int16)s);
Console.WriteLine("s2 as Int16 (error): {0}", (Int16)s2);

输出

Runtime error    time: 0.03 memory: 36592 signal:-1
Types: System.Int16 and System.Int32
s as Int16 (works): 10

从注释中,将Int32强制转换为Int16是直接有效的,因为编译器知道它们可以被转换并自动执行。当你使用一个裸露的对象时,尽管它会失明,不会自动转换。这将起作用,例如:

    Console.WriteLine("s2 as Int16 (works): {0}", (Int16)((Int32)s2));

这取决于应用程序中的"s"。当您调用Convert.ToInt16(s(时,您可以安全地尝试将任何对象s强制转换为Int16。如果"s"以前被声明为对象(对象s(,那么它可以从对象中取消框10。但是因为它是一个对象,所以不能显式地将它强制转换为Int16,因为毕竟,您确实将它声明为对象。请参阅以下代码:

object s;
s = new object();
s = 10;
Int16 newInt = (Int16)s; // This will throw, because s is actually an object
Int16 newInt = Convert.ToInt16(s); // This will not fail, because the convert is actually holding a value of 10.

开箱过程中的装箱值类型实例,您应该注意以下几点:

  1. 包含在装箱的值类型实例上的值为null,引发NullReferenceException异常。

  2. 如果不需要对象的引用点,则装箱的值类型实例将引发InvalidCastException异常。

第二个意味着以下代码不能正常工作:

s = new object();
s = 10;
Console.WriteLine("{0}", Convert.ToInt16(s));
Console.WriteLine("{0}", (Int16)s);//throws an InvalidCastException exception

该逻辑可以获得由装箱的Int32引用的s,并将其转换为INT6。对象上的取消装箱操作只能转换为取消装箱的值类型,在本例中为Int32。以下是正确的措辞:

下面的行解决了您的问题

Console.WriteLine("{0}", (Int16)(int)s); / / first unboxing of the correct type, and then transition