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()
是类型安全转换。但是,是什么让这里有所不同呢?也许这是个愚蠢的问题,但我很困惑。请帮我澄清一下,并纠正我的错误。
数字文字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#阅读器来说,short
和Int16
的名称对于16位整数是可互换的,int
和Int32
的名称对于32位整数也是可互换的。在C#中,short
和int
分别是.NET类型Int16
和Int32
的别名。
您的代码违反了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.
开箱过程中的装箱值类型实例,您应该注意以下几点:
-
包含在装箱的值类型实例上的值为null,引发NullReferenceException异常。
-
如果不需要对象的引用点,则装箱的值类型实例将引发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