一次简单的拆箱操作,竟然出来了异常,导致APP在iOS手机上面闪退了。
对面的异常进行反思和总结如下:
一、装箱和拆箱
装箱:把值类型转成引用类型
拆箱:把引用类型转成值类型
从定义中可以看出装箱和拆箱操作只可能发生在值类型之间的转换,引用类型之间是不会出现装箱和拆箱操作的。
装箱:object obj=1;
上述代码即为一次装箱过程。系统首先会建立一个索引为[0] object类型的局部变量,将整形数1从栈中取出放在栈顶,执行box指令并在托管堆上申请System.Int32所需内存空间。将栈上的变量弹出存储到索引为0的局部变量中。此操作不可避免的要在堆上申请内存空间,并将堆栈上的值类型数据复制到申请的堆内存空间上,这肯定是要消耗内存和cpu资源的。
拆箱:int x=(int)obj;
上述代码即为一次拆箱过程。系统首先会建立一个索引为[1]的int32类型局部变量,将堆上索引为[0]的变量值取出压入栈顶,执行unbox.any指令,生成System.Int32地址指针并读取数据存入栈。后将栈上的变量存储到索引为[1]的int32类型变量中。拆箱操作的执行过程和装箱操作过程正好相反,是将存储在堆上的引用类型值转换为值类型并给值类型变量。
由于装箱操作和拆箱操作是要额外耗费cpu和内存资源的,所以项目开发中尽量使用泛型定义来避免装箱和拆箱的出现。
二、数字类型之间的转换--(int)和int.Parse()和int.TryParse()和Convert.ToInt32()
private void ConvertType()
{
////////////////////////////////////////////////////////////////null type
int val1 = Convert.ToInt32(null); //0
//int val2 = int.Parse(null); //Error: System.ArgumentNullException:“值不能为 null。Arg_ParamName_Name”
int val3; //0
bool bVal3 = int.TryParse(null, out val3);//false
//int val4 = (int)null; //Error: 无法将 null 转换为int,因为后者是不可以为null的值类型
////////////////////////////////////////////////////////////////number type
float f = 1.1111f;
int val5 = Convert.ToInt32(f);//1 //采取的取舍是进行四舍五入
//int val6 = int.Parse(f.ToString());//Error: System.FormatException:“输入字符串的格式不正确。”
int val7;//0
bool bVal7 = int.TryParse(f.ToString(), out val7);//false
int val8 = (int)f;//1 //截取浮点型的整数部分,忽略小数部分。即向下取整
long l = 9111111111111111111;
//int val9 = Convert.ToInt32(l);//Error; System.OverflowException:“值对于 Int32 太大或太小。”
//int val10 = int.Parse(l.ToString());//Error: System.OverflowException:“值对于 Int32 太大或太小。”
int val11;//0
bool bVal11 = int.TryParse(l.ToString(), out val11);//false
int val12 = (int)l;//1726247367
////////////////////////////////////////////////////////////////string type
string s1 = "";
//int val13 = Convert.ToInt32(s1);//Error: System.FormatException:“输入字符串的格式不正确。”
//int val14 = int.Parse(s1);//Error: System.FormatException:“输入字符串的格式不正确。”
int val15;//0
bool bVal15 = int.TryParse(s1, out val15);//false
//int val16 = (int)s1;//Error: 无法将string转换为int
string s2 = "1.111";
//int val17 = Convert.ToInt32(s2);//Error: System.FormatException:“输入字符串的格式不正确。”
//int val18 = int.Parse(s2);//Error: System.FormatException:“输入字符串的格式不正确。”
int val19;//0
bool bVal19 = int.TryParse(s2, out val19);//false
//int val20 = (int)s1;//Error: 无法将string转换为int
Console.WriteLine("ConvertType Over");
}
对上面的测试代码进行总结:
1、null 空类型的转换:int.Parse()和直接强转是会报错的,其他转换返回0
2、number 数字类型的转换:Convert.ToInt32()是参与四舍五入取值,强转是直接向下取整。对于大值转向小值,Convert.ToInt32和int.Parse都会报错,
虽然强转不会报错,但是精度不对,会对原数据进行截取,结果也是错误的。
3、string 字符串类型的转换:对于空字符和浮点数的string的转换int,只有int.TryParse不会报错,其他都会报错。策划配置表经常出现类似的配置问题,需要注意。
综上,我们对数据转换要特别谨慎,选择合适的函数,才能保证不会出错。建议如果是数值类型直接的转换直接可以强转。如果是字符串类型的转换建议int.Parse和int.TryParse
如果是装拆箱建议用Convert.ToInt32。实在不知道选择哪个类型建议用int.TryParse,做好对转换返回值bool的判断就可以了
网友评论