Menu

C# 字符串转 int 与类型转换:Parse、TryParse、Convert

如何在 C# 中用 int.Parse、int.TryParse 和 Convert.ToInt32 把字符串转换为 int,隐式转换和显式转换如何工作,为什么把 double 强制转换为 int 会截断,as 和 is 运算符,以及为什么 “1.5” 可能被解析成 15。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

C# 从不自行在不相关的类型之间转换。包含数字的字符串仍然是字符串,double 也不会悄悄变成 int。你需要显式地转换,而用哪种工具取决于你要转换什么:把文本转换为数字(解析),把一种数值类型转换为另一种(强制转换),或者把对象转换为更具体的类型(as、is)。

字符串转 int:Parse、TryParse 和 Convert

把文本转换为 int 有三种标准方法:

输出:

2500
TryParse ok: 1250
TryParse failed, d = 0
42
-17

int.TryParse 返回一个 bool,并把结果写入一个 out 变量,失败时该变量被设为 0。由于用户输入的任何东西出错都很正常,TryParse 是处理输入、文件和查询字符串时的默认选择。每种数值类型都有同样的方法:long.TryParse、double.TryParse、decimal.Parse 等等。

遇到错误输入时各自的表现

这三种方法唯一的区别在于它们如何失败:

输出:

int.Parse(null) throws ArgumentNullException
Convert.ToInt32(null) = 0
int.Parse("abc") throws FormatException
int.Parse("12.5") throws FormatException
int.Parse("1,000") throws FormatException
int.Parse("9999999999") throws OverflowException
int.Parse("") throws FormatException

FormatException 带着那条熟悉的消息 “Input string was not in a correct format”(在 .NET 8 及更高版本中是 “The input string '12.5' was not in a correct format”,会引用出错的文本),它是 C# 最常见的运行时错误之一:"12.5" 不是 int,"1,000" 也不是。要接受这些写法,可以按 decimal 解析,或者告诉解析器允许哪些样式:

输出:

1000
255
13
10

区域性:为什么 “1.5” 可能变成 15

解析默认使用当前区域性,而不同区域性的分隔符并不一致。在德语和其他几种欧洲区域性中,小数分隔符是逗号,句点则用来给千位分组。同一个字符串会得出不同的数字:

输出:

1.5
15
1.5

读取数据文件、JSON、配置或任何机器生成内容的代码,在解析和格式化时都应该始终传入 CultureInfo.InvariantCulture。否则,同一个程序在开发者的机器上运行正常,到了设置成另一种语言的服务器上,却会读错每一个数字。只有对用户输入或给人阅读的文本,才使用当前区域性。

隐式和显式的数值转换

扩大转换会隐式进行:int 到 long、int 到 double、float 到 double、int 到 decimal。可能丢失数值大小或小数部分的转换,需要显式转换 (type)value。有一个例外需要记住:int 或 long 到 float,以及 long 到 double,虽然可能丢失精度,却是隐式的:float f = 16_777_217; 能通过编译,实际存储的是 16777216。

输出:

9 -9
10
2
4
705032704
9.99
7 7.0 7

要记住三件事。从浮点数到整数的强制转换会截断,而不是四舍五入。Convert.ToInt32(double) 会舍入,使用的是银行家舍入法(正好一半时舍入到偶数那一边)。超出范围的整数强制转换会悄无声息地回绕,除非它运行在 checked 上下文中,那时会抛出 OverflowException(请参阅 数据类型)。

int x = 3.7; 是一个编译错误(CS0266:cannot implicitly convert type 'double' to 'int', an explicit conversion exists),这是编译器在请你在强制转换和舍入方法之间做出选择。

把数字和其他类型转换为字符串

每种类型都有 ToString(),数值类型还接受格式字符串。字符串插值调用的也是同样的格式化:

输出:

42
000042
1234.50
1,234.50
$1,234.50
FF
1010
True
Order 000042: 1234.50

格式代码(D、F、N、C、X、P、E)以及 "0.00" 这样的自定义模式,请参阅 字符串插值。

字符与布尔值

输出:

7
55
7
7
A
True
False
1
False

(int)'7' 是 55,即这个字符的编码,而不是 7。想对一个数的各位数字求和的人常常在这里栽跟头;请减去 '0',或者使用 char.GetNumericValue。bool.Parse 接受任意大小写的 “true” 和 “false”,其他一概不接受(“yes” 和 “1” 都会抛出异常)。

引用转换:强制转换、as 和 is

对于类类型,强制转换会在运行时检查对象的实际类型。向上转换为基类是隐式的。向下转换为派生类则需要显式转换,如果对象实际上是别的类型,就会抛出 InvalidCastException:

输出:

4242
True
Card ending 4242, 50.00
InvalidCastException
5
cannot unbox int as long

需要根据类型分支时,优先使用带变量的 is:它只检查一次,不会抛出异常,而且新变量只在检查成功的范围内有效。如果出现其他类型就是应该大声报错的 bug,就用普通的强制转换。装箱的 int 这种情况,常常困扰从 object 集合或 DataRow 单元格中读取数字的人:先拆箱为确切的类型((long)(int)boxed),或者使用能处理任何数值类型的 Convert.ToInt64(boxed)。

常见问题

C# 中如何把字符串转换为 int?

当文本来自用户、文件或网络时,使用 int.TryParse(text, out int number):文本不是有效数字时,它返回 false 而不是抛出异常。当无效文本属于 bug、抛出异常才是正确反应时,使用 int.Parse(text)。Convert.ToInt32(text) 的行为和 int.Parse 一样,只是遇到 null 时返回 0。

int.Parse 和 Convert.ToInt32 有什么区别?

对于字符串,它们几乎一样:遇到 "abc" 这样的文本都会抛出 FormatException,遇到超出范围的数字都会抛出 OverflowException。区别在于 null:int.Parse(null) 会抛出 ArgumentNullException,而 Convert.ToInt32(null) 返回 0。Convert.ToInt32 还接受其他类型(double、bool、object),并且会把 double 舍入到最接近的偶数整数,而不是截断。

“Input string was not in a correct format”是什么意思?

这是 int.Parse、double.Parse 或 Convert.ToInt32 抛出的 FormatException 的消息(在 .NET 8 及更高版本中,它的内容是 "The input string 'abc' was not in a correct format",会引用出错的文本),出现在文本不是预期格式的数字时:含有字母、空字符串、解析 int 时带有小数点,或者带有千位分隔符。改用 TryParse 可以在不抛出异常的情况下处理错误输入,同时要检查这个数字是按哪种区域性写的。

C# 中如何把 double 强制转换为 int?

写一个显式转换:int n = (int)price;。这种转换会向零截断,所以 (int)9.99 是 9,(int)-9.99 是 -9。如果想四舍五入,请用 (int)Math.Round(price),并注意 Math.Round 默认会把正好一半的值舍入到最接近的偶数;如果要课本上的四舍五入,请传入 MidpointRounding.AwayFromZero。

C# 中 as 和强制转换有什么区别?

如果对象不是 Dog,强制转换 (Dog)animal 会抛出 InvalidCastException。animal as Dog 则会返回 null,所以后面必须跟一个 null 检查,而且它只适用于引用类型和可空类型。现代的替代写法是 is 模式:if (animal is Dog dog) { ... } 一步完成检查和转换。

Coddy 编程语言插图

和 Coddy 一起学编程

开始