C#笔记(6)类型转换
C# 类型转换
类型转换从根本上说是类型铸造,或者说是把数据从一种类型转换为另一种类型。在 C# 中,类型铸造有两种形式:
- 隐式类型转换 - 这些转换是 C# 默认的以安全方式进行的转换, 不会导致数据丢失。例如,从小的整数类型转换为大的整数类型,从派生类转换为基类。
- 显式类型转换 - 显式类型转换,即强制类型转换。显式转换需要强制转换运算符,而且强制转换会造成数据丢失。
值类型间的转换
在C#的运算中,要求各被运算单元的数据类型是一致的,且运算结果将与被运算单元保持一致。
例如:10/4
的运算中,被运算的两个数字10与4都属于int 类型,则运算结果也应该是int类型的,所以运算结果是2,而不是2.5。实际开发过程中,对数据的单纯操作可能无法满足现有的需求,这时就需在不同数据类型之间进行相应的转换。C# 提供了2种转换方式:
- 自动类型转换(又叫:隐式类型转换 或 向上转型)
- 强制类型转换(又叫:显示类型转换 或 向下转型)
自动类型转换
自动类型转换,又叫做:隐式转型 或 向上转型。是 C# 默认的以安全方式进行的转换, 不会导致数据丢失。
自动转型常见的场景:
当被运算单元的数据类型不同时,程序将尝试可行的自动转换(提升)数据类型。关于自动转型的另外一种说法是:将一个范围小的数据转为较大类型的数据时,系统会自动进行类型转换
例如:15000 * 0.25 的运算实际为 int 与 double 的运算,程序执行时,会将 15000 按照 double 类型处理,以保证运算结果是准确的。
强制类型转换
- 很明显,上两页练习中的程序代码是存在错误的。如何解决上面的问题呢? 就需要使用:强制类型转换
强制类型转换,又叫向下转型。指的是将一个范围大的数据转为一个范围小的数据类型。 - 基本语法:
( 要转换成的类型 ) 具体要转换的数据或变量
- 例如: ( int ) 3.1415926 表示将double 类型的数据3.1415926 强制转换为 int 类型,结果为: 3 。
- 强制转型有风险,有可能引起数据溢出或精度丧失,造成最后数据结果不准确的情况。所以:一般情况下,不推荐使用强制类型转换方式。
- 例如:
1 | int i = 256 ; |
上面两行代码中,声明 int 型变量 i 值256,然后将 i 的值赋值给 byte 型变量 b,打印b时结果为:0 ,出现这种结果是因为byte(1个字节)在内存中存储4个字节的int型变量时无法容纳,故出现数据溢出情况,导致运算结果不准确。
隐式转换和显式转换
隐式转换:C# 默认的以安全方式进行的转换。本质是从小存储容量数据类型自动转换为大存储容量数据类型,从派生类转换为基类。
实例:
1 | namespace TypeConvertion |
显式转换:通过用户使用预定义的函数显式完成的,显式转换需要强制转换运算符。
转换类型的范围大小和从属关系和隐式转换相反。显式转换可能会导致数据出错,或者转换失败,甚至无法编译成功。
实例:
1 | double dnum = 100.1; |
- 运行结果:
1 | FALSE |
C# 类型转换方法(Convert类)
方法 | 描述 |
---|---|
ToBoolean | 如果可能的话,把类型转换为布尔型。 |
ToByte | 把类型转换为字节类型。 |
ToChar | 如果可能的话,把类型转换为单个 Unicode 字符类型。 |
ToDateTime | 把类型(整数或字符串类型)转换为 日期-时间 结构。 |
ToDecimal | 把浮点型或整数类型转换为十进制类型。 |
ToDouble | 把类型转换为双精度浮点型。 |
ToInt16 | 把类型转换为 16 位整数类型。 |
ToInt32 | 把类型转换为 32 位整数类型。 |
ToInt64 | 把类型转换为 64 位整数类型。 |
ToSbyte | 把类型转换为有符号字节类型。 |
ToSingle | 把类型转换为小浮点数类型。 |
ToString | 把类型转换为字符串类型。 |
ToType | 把类型转换为指定类型。 |
ToUInt16 | 把类型转换为 16 位无符号整数类型。 |
ToUInt32 | 把类型转换为 32 位无符号整数类型。 |
ToUInt64 | 把类型转换为 64 位无符号整数类型。 |
xxx.Parse
xxx.Parse
就是把String
转换成int,char,double....
等,也就是xxx.Parse(string)
括号中的一定要是string。
类型之间的转换 - Convert 和 Parse
1 | int a = 123; |
xxx.TryParse(string s,out xxx i)
1 | int.TryParse(string s,out int i) |
该方式也是将数字内容的字符串转换为int类型,但是该方式比int.Parse(string s) 好一些,它不会出现异常,最后一个参数result是输出值,如果转换成功则输出相应的值,转换失败则输出0。
1 | class test |
结果输出:
1 | abcd False 0 |
浅谈 string 转 int 与抛异常
string 字符串类型和 int 也是可以转换的。下一行的代码给出错误的转换方法。
1 | string a = "123"; // 将a设置为字符串“123” |
上述代码,毋庸置疑,肯定是错误的。VS 在编译时就过不了。那么,string 该怎么转换成 int 呢?
这里,我们需要用到 int.Parse(),核心代码为:
1 | string a = "123"; // 将a设置为字符串“123” |
如果仅仅是这样,是没有问题的,但是,我们下面再来做一个实例。
用户输入一个数字,而电脑将计算出这个数字加上1以后的答案,并且显示出来。
用户输入的东西,即 Console.ReadLine() ,一定是以字符串形式表现的。
于是,运用之前的方法,我们可以写出以下的代码:
1 | class 测试 |
当程序运行时,会出现:
1 | 输入数字,将计算出它加一的答案 |
这样就很完美了吗?不!!
如果用户输入并非数字的其他字符,如汉字,会发生什么情况?
此时,用户输入 王 ,显然,程序将无法继续运行下去,因为int类型只能存整数,不能存字符。
这时,程序就会抛出异常。
如果用 VS 编,你还会看到异常类型:FormatException。
所以,为了保险,可以用try、catch来解决此问题。核心代码为:
1 | try |
try 在英语中就是尝试的意思。在这段代码中,try{} 部分,顾名思义,也就是去尝试进行下面的代码。catch{} 部分,则是检测异常。这样,在出现异常时,catch 就能捕获到异常,从而程序并不会停止。
则这段程序,完整的代码应该为:
1 | using System; |
这样,如果我输入了 王 ,程序结果为:
1 | 无法转换 |
数据精度
(int)xxx
例如: ( int ) 3.1415926
表示将double
类型的数据3.1415926
强制转换为 int 类型,结果为:3
。
Convert.ToInt32() 与 int.Parse() 的区别
没搞清楚 Convert.ToInt32 和 int.Parse() 的细细微区别时千万别乱用,否则可能会产生无法预料的结果.
举例来说:假如从 url 中取一个参数 page 的值,我们知道这个值是一个 int,所以即可以用 **Convert.ToInt32(Request.QueryString[“page”])**,也可以用 **int.Parse(Request.QueryString[“page”])**,但是如果 page 这个参数在 url 中不存在,那么前者将返回 0,0 可能是一个有效的值,所以你不知道 url 中原来根本就没有这个参数而继续进行下一下的处理,这就可能产生意想不到的效果,而用后一种办法的话没有 page 这个参数会抛出异常,我们可以捕获异常然后再做相应的处理,比如提示用户缺少参数,而不是把参数值当做 0 来处理。
这两个方法的最大不同是它们对 null 值的处理方法: Convert.ToInt32(null) 会返回 0 而不会产生任何异常,但 int.Parse(null) 则会产生异常。
对数据进行四舍五入时候的区别
- Convert.ToInt32(double value) 如果 value 为两个整数中间的数字,则返回二者中的偶数;即 3.5 转换为 4,4.5 转换为 4,而 5.5 转换为 6。不过 4.6 可以转换为 5,4.4 转换为 4 。
- int.Parse(“4.5”) 直接报错:**”输入字符串的格式不正确”**。
- int(4.6) = 4 Int 转化其他数值类型为 Int 时没有四舍五入,强制转换。
对被转换类型的区别 int.Parse 是转换 String 为 int, Convert.ToInt32 是转换继承自 Object 的对象为 int 的(可以有很多其它类型的数据)。你得到一个 object 对象, 你想把它转换为 int, 用 int.Parse 就不可以, 要用 Convert.ToInt32。
Convert.ToInt32() 、int.TryParse() 和 int.Parse()
对于转换对象,Convert.ToInt32() 可以为多种类型(例出数字类型外 bool,DateTime 等),int.TryParse() 和 int.Parse() 只能是整型字符串类型(即各种整型 ToString() 之后的形式,不能为浮点型,否则 int.Parse() 就会出现输入的字符串格式不正确的错误,int.TryParse() 也会返回 false,输出参数为 0 ,(int)只能是数字类型(例 float,int,uint等);
对于空值 NULL,从运行报错的角度讲,(int) 强制转换和 int.Parse() 都不能接受 NULL;Convert.ToInt32() 其实是在转换前先做了一个判断,参数如果为 NULL,则直接返回 0,否则就调用 int.Parse() 进行转换,int.TryParse() 其实是对 int.Parse() 做了一个异常处理,如果出现异常则返回 false,并且将输出参数返回 0;
针对于浮点型的取舍问题,浮点型只有 Convert.ToInt32() 和 (int) 能进行转换,但是也是进行取舍了的,Convert.ToInt32() 采取的取舍是进行四舍五入,而 (int) 则是截取浮点型的整数部分,忽略小数部分,例如 Convert.ToInt32(1.499d) 和 (int)1.499d 都返回 1,Convert.ToInt32(1.5d) 返回 2,而 (int)1.5d 还是返回 1;
关于溢出,将大的数据类型转换为小的数据类型时 Convert.ToInt32() 和 int.Parse() 都会报溢出错误,值对于 Int32 太大或太小,而 (int) 不报错,但是返回值为 -1。
如此可见,我们在进行数据转换前选择转换方法要谨慎,如果是数字类型可以考虑直接用(int)强制转换,如果是整型字符串类型的,考虑用 int.Parse() 进行转换,如果不是这两种类型,再考虑用 Convert.ToInt32() 进行转换。
Convert.ToDouble与Double.Parse的区别。
实际上 Convert.ToDouble 与 Double.Parse 较为类似,实际上 Convert.ToDouble内部调用了 Double.Parse:**
对于参数为null的时候:
- Convert.ToDouble参数为 null 时,返回 0.0;
- Double.Parse 参数为 null 时,抛出异常。
对于参数为””的时候:
- Convert.ToDouble参数为 “” 时,抛出异常;
- Double.Parse 参数为 “” 时,抛出异常。
其它区别:
- Convert.ToDouble可以转换的类型较多;
- Double.Parse 只能转换数字类型的字符串。
- Double.TryParse 与 Double.Parse 又较为类似,但它不会产生异常,转换成功返回 true,转换失败返回 false。最后一个参数为输出值,如果转换失败,输出值为 0.0。
附测试代码:
1 | using System; |
装箱和拆箱
- 装箱:值类型转换为对象类型, 实例:
1 | int val = 8; |
- 拆箱:之前由值类型转换而来的对象类型再转回值类型, 实例:
1 | int val = 8; |
只有装过箱的数据才能拆箱