1类型转换是什么
上一节留的问题:3.5 非要放进 int 怎么办?在前面加一对括号写上 int,结果是 3。下面的例子多数是顶级语句写法(不写类和 Main,代码从第一行开始执行)。
| 1 | int n = (int)3.5; | // (int) 把 3.5 转成 int,小数部分去掉,n = 3 |
| 2 | Console.WriteLine(n); | // 输出 3 |
把一个类型的值变成另一个类型,就叫类型转换。C# 的类型转换分两种:隐式转换和显式转换。
2隐式转换
不用写任何代码,编译器(把代码翻译成程序的工具)自动帮你转,条件是从小范围转到大范围。byte 只占 1 个字节,int 占 4 个字节,10 从小的放进大的,一点不丢。
| 1 | byte b = 10; | // byte 变量 b,值是 10 |
| 2 | int i = b; // 隐式转换,不需要显式转换 | // 直接把 byte 赋给 int,编译器自动转 |
| 3 | Console.WriteLine(i); | // 输出 10 |
同理,int 能直接放进 long,float 能直接放进 double,运行结果 42 和 1.5 原样不变。反过来,把 int 直接放进 byte,编译器不答应:
| 1 | int i = 10; | // int 变量 i,值是 10 |
| 2 | byte b = i; | // 大范围的 int 直接放进小范围的 byte |
Program.cs(2,10): error CS0266: 无法将类型“int”隐式转换为“byte”。存在一个显式转换(是否缺少强制转换?)
教程还提到,派生类转基类也是隐式转换,讲继承时再说。
3显式转换
显式转换也叫强制类型转换:在值前面加一对括号,括号里写目标类型。
| 2 | byte b = (byte)i; // 显式转换,需要使用强制类型转换符号 | // i 是 10,(byte) 把它转成 byte |
| 3 | Console.WriteLine(b); | // 输出 10 |
溢出
强制转换是可能丢数据,不是一定丢:10 放得下就一点不丢。可 byte 最大只到 255,300 比 256 多出 44,数值绕回起点只剩 44,这叫溢出。
| 2 | byte b = (byte)i; | // i 是 300,强制转成 byte:300 - 256 = 44 |
| 3 | Console.WriteLine(b); | // 输出 44 |
截断
double 转 int,小数部分被直接去掉,这叫截断,不是四舍五入,和溢出是两回事。
| 1 | double doubleValue = 3.14; | // double 变量,整数部分 3,小数部分 0.14 |
| 2 | int intValue = (int)doubleValue; // 强制从 double 到 int,数据可能损失小数部分 | // 去掉 0.14,只剩 3 |
| 3 | Console.WriteLine(intValue); | // 输出 3 |
| 4 | Console.WriteLine((int)3.99); | // 3.99 也是去掉小数,输出 3,不是 4 |
教程里的完整例子把 5673.74 强制转成 int,输出 5673,小数部分没了。
int 转 float
int 转 float 允许隐式转换,不写 ( 也行(实测 42 转完还是 42)。但 float 只能精确存 7 位左右的数字,大整数会丢精度:
| 1 | int big = 16777217; | // 一个 8 位数 |
| 2 | float f = big; | // 不写括号,int 自动转成 float |
| 3 | Console.WriteLine(f); | // 输出 16777216,最后一位变了 |
转成字符串
数字变字符串不能用强制转换,写成 ( 编译报错 CS0030(无法将类型“int”转换为“string”),要调用 ToString() 方法:
| 2 | string stringValue = intValue.ToString(); // 将 int 转换为字符串 | // intValue 是 int 123,变成字符串 "123" |
| 3 | Console.WriteLine(stringValue + "4"); | // 字符串 + 字符串是接起来,输出 1234,不是 127 |
4Convert 类
除了括号,C# 在 System 命名空间(存放一组类的“文件夹”)的 Convert 类里准备了一整套转换方法,名字都是 To 加类型名,用的是正式类型名:Int32 就是 int,Single 就是 float。教程列的 16 个都真跑过:
查看完整代码(16 行)
| 1 | Console.WriteLine(Convert.ToBoolean("true")); | // 转成 bool,输出 True |
| 2 | Console.WriteLine(Convert.ToByte("255")); | // 转成 byte,输出 255 |
| 3 | Console.WriteLine(Convert.ToChar(65)); | // 65 转成字符,输出 A |
| 4 | Console.WriteLine(Convert.ToDateTime("2026-10-28").ToString("yyyy-MM-dd")); | // 转成日期类型 DateTime,按年-月-日打印 2026-10-28 |
| 5 | Console.WriteLine(Convert.ToDecimal(0.1)); | // 转成 decimal,输出 0.1 |
| 6 | Console.WriteLine(Convert.ToDouble("2.5")); | // 转成 double,输出 2.5 |
| 7 | Console.WriteLine(Convert.ToInt16("-300")); | // 转成 short,输出 -300 |
| 8 | Console.WriteLine(Convert.ToInt32("123")); | // 转成 int,输出 123 |
| 9 | Console.WriteLine(Convert.ToInt64("9000000000")); | // 转成 long,输出 9000000000 |
| 10 | Console.WriteLine(Convert.ToSByte("-5")); | // 转成 sbyte(带符号的 byte),输出 -5 |
| 11 | Console.WriteLine(Convert.ToSingle("1.25")); | // 转成 float,输出 1.25 |
| 12 | Console.WriteLine(Convert.ToString(42) + "!"); | // 转成 string 再接上 "!",输出 42! |
| 13 | Console.WriteLine(Convert.ChangeType("7", typeof(int))); | // ChangeType:转成 typeof(int) 取到的 int 类型,输出 7 |
| 14 | Console.WriteLine(Convert.ToUInt16("65535")); | // 转成 ushort,输出 65535 |
| 15 | Console.WriteLine(Convert.ToUInt32("4000000000")); | // 转成 uint,输出 4000000000 |
| 16 | Console.WriteLine(Convert.ToUInt64("18000000000000000000")); | // 转成 ulong,输出 18000000000000000000 |
方法表要改正的地方
- 方法名是
ToSByte(b 大写),没有ToSbyte;也没有ToType,想转成指定类型用ChangeType。
| 1 | sbyte s = Convert.ToSbyte("-5"); | // b 写成小写 |
| 2 | int n = Convert.ToType("7"); | // Convert 里没有 ToType |
Program.cs(1,19): error CS0117: “Convert”未包含“ToSbyte”的定义 Program.cs(2,17): error CS0117: “Convert”未包含“ToType”的定义
ToDateTime能转日期字符串,但不能转整数:Convert.会抛出 InvalidCastException。ToDateTime( 20261028)
Convert 和括号不一样
字符串 "123" 转成整数后再加 1 得 124,确实是数字了;字符串是 null(空,什么都没有)时,结果是 0。
| 2 | int number = Convert.ToInt32(str); // 转换成功,number为123 | // str 是 "123" |
| 3 | Console.WriteLine(number + 1); | // 数字相加:123 + 1,输出 124 |
字符串是 abc,就抛出 FormatException(异常就是运行时出的错,这个表示格式不对),程序到这里就停了:
| 1 | string str = "abc"; | // 不是数字的字符串 |
| 2 | int number = Convert.ToInt32(str); | // 读不成整数,抛出异常 |
查看完整输出(4 行)
Unhandled exception. System.FormatException: The input string 'abc' was not in a correct format. at System.Number.ThrowFormatException[TChar](ReadOnlySpan`1 value) at System.Convert.ToInt32(String value) at Program.<Main>$(String[] args) in 类型转换/c-abc/Program.cs:line 2
300 用括号转 byte 得 44,用 Convert. 却抛出 OverflowException:装不下就报出来,不悄悄变成别的数,这就是说它安全的意思。小数转整数时,Convert 取最接近的整数:
| 1 | Console.WriteLine((int)3.7); | // 括号:截断小数,输出 3 |
| 2 | Console.WriteLine(Convert.ToInt32(3.7)); | // Convert:取最接近的整数,输出 4 |
5ToString 实例
教程定义了 int、float、double、bool 四个变量,再用 ToString() 逐个转成字符串打印,bool 打印出来是首字母大写的 True。
75 53.005 2345.7652 True
6注意事项
- 隐式转换只能从小范围到大范围,反过来不行。
- 显式转换可能丢数据、丢精度,转之前要想清楚放不放得下。
- 对象类型之间转换,要先检查能不能转、安不安全,这一条等讲类的时候再展开。
7Convert、Parse 和 TryParse
这三种方法最常用来把字符串变成数字。double. 用法和 Convert 差不多;字符串要不是数字,也会抛出 FormatException,程序停下。
| 1 | string str = "123.45"; | // 写着数字的字符串 |
| 2 | double d = double.Parse(str); | // Parse:把字符串解析成 double |
| 3 | Console.WriteLine(d); | // 输出 123.45 |
TryParse 不会让程序停下:成功返回 true,转出来的数从 out 参数(方法通过它把结果交回来)那里拿,所以后面配一个 if。下面 str 是 "123.45",d 是前面声明的 double 变量。
| 3 | bool success = double.TryParse(str, out d); | // 试着转换:成功返回 true,结果放进 d |
| 4 | | |
| 5 | if (success) { | // 成功了(if 开始) |
| 6 | Console.WriteLine("转换成功: " + d); | // 输出 转换成功: 123.45 |
| 7 | } else { | // 没成功(else 开始) |
| 8 | Console.WriteLine("转换失败"); | // str 换成 "abc" 时走这里,输出 转换失败 |
| 9 | } | // if-else 结束 |
用户输入的东西不一定是数字,这时用 TryParse 最稳。
8自定义类型转换
C# 允许给自己写的类型定义转换,用到 implicit(隐式)或 explicit(显式)关键字和 operator(定义运算或转换的写法,后面会讲)。教程的例子是华氏温度类 Fahrenheit,度数存在属性 Degrees 里(类和属性后面会讲)。
| 13 | public static implicit operator double(Fahrenheit f) | // 规定 Fahrenheit 可以自动转成 double |
| 14 | { | // 转 double 的 operator 开始 |
| 15 | return f.Degrees; | // 转出来的就是度数 |
| 16 | } | // 转 double 的 operator 结束 |
| 17 | | |
| 18 | // 显式转换从double到Fahrenheit | |
| 19 | public static explicit operator Fahrenheit(double d) | // 规定 double 转回 Fahrenheit 必须写括号 |
| 20 | { | // 转 Fahrenheit 的 operator 开始 |
| 21 | return new Fahrenheit(d); | // 用这个度数新建一个 Fahrenheit 对象 |
| 32 | double temp = f; // 隐式转换 | // f 是度数 98.6 的 Fahrenheit 对象,自动转成 double |
| 33 | Console.WriteLine("After implicit conversion to double: " + temp + " degrees"); | // 输出 98.6 |
| 34 | | |
| 35 | Fahrenheit newF = (Fahrenheit)temp; // 显式转换 | // 写括号把 double 转回 Fahrenheit |
运行出三行,都是 98.6 度:转过去又转回来,值没变。要是转回来时漏写 (,报的错和内置类型一样是 CS0266。类和 operator 的细节,后面讲类的时候再说。
9小结
- 隐式转换自动发生,用于安全的转换;显式转换要写括号,可能丢数据(溢出、截断)。
- Convert 类有一整套 To 方法,装不下会报异常,小数取最接近的整数。
- Parse 把字符串解析成各种类型,失败抛异常;TryParse 用返回值告诉你成没成功。
- Boolean、Int16、Int32 就是 bool、short、int 的正式名字。
- 一句话:放得下就自动转,放不下要亲手写括号,字符串得读出来才是数。
下一节:转换讲完了,这些值总得有个地方放——变量怎么声明、怎么起名、怎么赋初值?
