文章目录
-
-
- [1. 核心区别:暴力型 vs. 稳重型](#1. 核心区别:暴力型 vs. 稳重型)
-
- [Parse: 默认数据正确](#Parse: 默认数据正确)
- [TryParse: 典型的 C# 模式](# 模式)
- 示例
- [2. 执行流程图](#2. 执行流程图)
- [3. 性能](#3. 性能)
- [4. 高性能方案](#4. 高性能方案)
-
- [4.1. 高性能转换:Span<char> 与 Utf8Parser](#4.1. 高性能转换:Span<char> 与 Utf8Parser)
- [4.2. 执行流程:内存视角](#4.2. 执行流程:内存视角)
- [4.3. 类型转换对比](#4.3. 类型转换对比)
- [5. 易混淆](#5. 易混淆)
-
在 C# 处理字符串转数字(或者转日期、枚举等类型)时, Parse 和 TryParse 是最常用的两个工具。它们的区别在于 对错误的处理态度 。
它是 .NET 中一种通用的设计模式。
几乎所有能够从字符串表达出的 内置基本类型 、日期时间 、甚至是你自定义的类,都可以支持这两个方法。
在 .NET 中,以下类型都标配了这两个方法:
- 数值类 :
long,double,float,decimal,byte,short等。 - 逻辑与字符 :
bool(能转 "True"/"False"),char。 - 时间与空间 :
DateTime,TimeSpan,Guid(全局唯一标识符)。 - 枚举 (Enum) :
Enum.TryParse<TEnum>(非常常用)。 - 网络与 IP :
IPAddress.Parse。
1. 核心区别:暴力型 vs. 稳重型
| 特性 | Parse (暴力型) | TryParse (稳重型) |
|---|---|---|
| 失败后果 | 直接抛出异常(报错),程序如果不捕获会崩溃。 | 返回 false,程序继续运行,不报错。 |
| 返回结果 | 返回转换后的目标类型(如 int)。 | 返回 bool;转换结果通过 out 参数输出。 |
| 性能 | 失败时性能极差(抛异常很耗资源)。 | 无论成功失败,性能都很稳定。 |
| 适用场景 | 你确信字符串一定是合法的(如配置文件)。 | 字符串来源不可靠(如用户输入、网页抓取)。 |
Parse: 默认数据正确
当你用 int.Parse("123") 时,你是在告诉编译器:"我打赌这货绝对是数字,如果不是,你就当场爆炸给我看"。
csharp
string input = "abc";
try
{
int result = int.Parse(input); // 这里会抛出 FormatException
}
catch (FormatException)
{
// 你必须手动处理异常
}
TryParse: 典型的 C# 模式
TryParse 采用了 "尝试-返回" 模式。它需要结合 out 关键字来接收结果。
csharp
string input = "123";
// 这种写法最常用:直接在参数位定义输出变量
if (int.TryParse(input, out int result))
{
// 转换成功,result 已经有值了
Console.WriteLine($"转换成功: {result}");
}
else
{
// 转换失败,result 会被赋予默认值(如 0)
Console.WriteLine("输入不是有效的数字");
}
示例
csharp
// 1. 数值类 (double, decimal 同理)
string scoreStr = "98.5";
if (float.TryParse(scoreStr, out float score))
Console.WriteLine($"分数: {score}");
// 2. 逻辑类 (不区分大小写,"true" 或 "True" 都能转)
string statusStr = "true";
if (bool.TryParse(statusStr, out bool isActive))
Console.WriteLine($"是否激活: {isActive}");
// 3. 字符类 (必须长度为 1)
string charStr = "A";
if (char.TryParse(charStr, out char letter))
Console.WriteLine($"字符: {letter}");
// 4. 时间类 (建议处理这种不确定来源的字符串)
string dateStr = "2026/01/19";
if (DateTime.TryParse(dateStr, out DateTime dt))
Console.WriteLine($"日期: {dt.ToShortDateString()}");
// 5. 跨度类 (处理"一段时间")
string spanStr = "00:30:00"; // 30分钟
if (TimeSpan.TryParse(spanStr, out TimeSpan interval))
Console.WriteLine($"间隔分钟: {interval.TotalMinutes}");
// 6. 唯一标识符 (GUID)
string guidStr = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
if (Guid.TryParse(guidStr, out Guid id))
Console.WriteLine($"ID有效: {id}");
// 7. 网络 IP (验证用户输入是否是合法 IP)
string ipStr = "192.168.1.1";
if (IPAddress.TryParse(ipStr, out IPAddress? address))
Console.WriteLine($"IP地址家族: {address.AddressFamily}");
// 8. 枚举类 (泛型写法)
string colorStr = "Green";
if (Enum.TryParse<System.Drawing.KnownColor>(colorStr, out var color))
Console.WriteLine($"枚举值: {color}");
分数: 98.5
是否激活: True
字符: A
日期: 2026/1/19
间隔分钟: 30
ID有效: f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4
IP地址家族: InterNetwork
枚举值: Green
| 类型 | 转换失败后的默认值 (default) |
|---|---|
| int, float, double | 0 |
| bool | False |
| DateTime | 0001/1/1 0:00:00 |
| Guid | 00000000-0000-0000-0000-000000000000 |
| IPAddress | null (因为它属于引用类型) |
2. 执行流程图

3. 性能
为什么说 Parse 在失败时性能差?
在 .NET 中,生成一个**异常堆栈(Exception Stack Trace)**是非常沉重的操作。如果你在处理一个包含 100 万行数据的文本,其中有 1 万行格式不对,用 Parse 会导致程序 CPU 飙升甚至卡死;而 TryParse 只是简单地返回一个布尔值,速度极快。
目前的趋势是尽量减少内存分配 。传统的 int.Parse(string) 需要一个完整的字符串对象。但在处理海量数据时,我们往往面对的是一个巨大的缓冲区(Buffer),并不想为每一段数字都创建一个子字符串。
4. 高性能方案
4.1. 高性能转换:Span 与 Utf8Parser
在现代 C# 开发中,如果你在处理底层的字节流或大型文本,你会用到 Span。
csharp
// 假设这是一段巨大的文本缓冲区,我们只关心索引 10 到 13 的数字
ReadOnlySpan<char> buffer = "Order-ID: 9527; User: Gemini".AsSpan();
ReadOnlySpan<char> slice = buffer.slice(10, 4); // 这里不产生新的字符串分配
if (int.TryParse(slice, out int orderId))
{
// 这种转换是在原始内存块上直接进行的,速度极快且零 GC 压力
Console.WriteLine($"订单号: {orderId}");
}
4.2. 执行流程:内存视角
传统的 Parse 就像是把书里的一页撕下来(创建新字符串),再看上面的字;而基于 Span 的转换就像是用放大镜直接在书页上看那一段。

4.3. 类型转换对比
除了 Parse 和 TryParse,其实还有两个兄弟你可能会碰到:
| 工具 | 适用场景 | 备注 |
|---|---|---|
| Convert.ToInt32() | 万金油,支持多种类型互转 | 内部其实也是调用了 Parse,但它能处理 null(返回 0 而不报错)。 |
| Explicit Cast (int)obj | 拆箱或已知类型的强制转换 | 必须是数字类型之间转换,不能把 "123" 字符串转成数字。 |
5. 易混淆
- out 关键字 : C# 中的一种参数修饰符。它允许方法将结果返回给调用者,即使方法本身的返回值已经被占用了(比如
TryParse的返回值被用来表示是否成功)。 - 异常 (Exception): 程序运行时的非正常行为。如果不处理,会导致程序崩溃(Crash)。
- 默认值 (Default Value) : 如果转换失败,
out参数会被赋予该类型的默认状态。对于int是0,对于bool是false,对于引用类型是null。 - 控制流 (Control Flow) : 程序执行的路径。
TryParse允许你通过if-else优雅地控制流程,而不是通过昂贵的try-catch。 - 内存分配 (Memory Allocation):在堆内存中开辟空间存储对象。分配越频繁,垃圾回收(GC)就越累,程序就会变慢。
- Span / ReadOnlySpan:C# 7.2+ 引入的神器,代表一段连续的内存。它像一个高效的窗口,让你操作数据而无需复制数据。
- GC 压力 (GC Pressure):由于频繁创建短命对象,导致垃圾回收器频繁工作。降低 GC 压力是提升系统吞吐量的关键。
- 拆箱 (Unboxing):将对象类型(Object)转换回值类型(如 int)的过程。这会有一定的性能开销。