IPAddress.TryParse 是验证 IP 字符串合法性最可靠方式,支持 IPv4/IPv6、不抛异常、性能高;需配合 Trim() 处理空格,AddressFamily 判断类型,禁用正则硬编码。

用 IPAddress.TryParse 判断字符串是否为合法 IP 地址最可靠
直接调用 IPAddress.TryParse 是 C# 中验证 IP 字符串合法性最稳妥的方式,它能同时处理 IPv4 和 IPv6,且不抛异常、不依赖正则规则维护。
常见错误是手写正则或只检查点号数量、数字范围——这些会漏掉边界情况(如 "256.1.1.1"、"192.168.01.1"、"::1"),甚至误判 IPv6 压缩格式。
-
IPAddress.TryParse内部做了完整协议解析,包括前导零校验、段数限制、IPv6 冒号展开等 - 它返回
bool,第二个参数是out IPAddress result,无需捕获异常,性能也比Try-Catch + IPAddress.Parse高得多 - 若只需判断合法性、不关心具体类型,可忽略输出参数:
IPAddress.TryParse(input, out _)
string input = "192.168.1.255";
if (IPAddress.TryParse(input, out _))
{
// 合法
}需要区分 IPv4 还是 IPv6?看 AddressFamily
仅靠 TryParse 成功无法知道是哪种 IP 类型,必须检查解析后的 IPAddress.AddressFamily。
容易踩的坑:用字符串 Contains(".") 或 ":" 来粗略判断——"::ffff:192.168.1.1" 是合法 IPv6 映射地址,含点号但不是 IPv4;"127.0.0.1" 也不含冒号,但不能反推所有不含冒号的就是 IPv4。
-
result.AddressFamily == AddressFamily.InterNetwork表示 IPv4 -
result.AddressFamily == AddressFamily.InterNetworkV6表示 IPv6 - 注意:某些 IPv4 映射的 IPv6 地址(如
::ffff:192.168.1.1)仍属于InterNetworkV6,不是 IPv4
if (IPAddress.TryParse(input, out var addr))
{
if (addr.AddressFamily == AddressFamily.InterNetwork)
{
// 确认为纯 IPv4
}
}别用正则硬刚 IP 验证,除非你真懂 RFC 4291 和 RFC 5952
网上流传的“IP 正则”多数只覆盖基础 IPv4,对 IPv6 几乎无效,且易被绕过。例如这个常见错误正则:^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$ —— 它拒绝 "0.0.0.0"(因未允许单个 0)、接受 "01.02.03.04"(前导零本应非法),更完全不支持 IPv6。
即使写全 IPv6 正则,也要处理压缩双冒号、大小写、嵌入 IPv4 等复杂情况,维护成本远高于调用现成 API。
- 正则适合做初步过滤(比如快速排除明显不含点/冒号的字符串),但不能作为最终验证手段
-
IPAddress.TryParse已经严格遵循 IETF 规范,没必要重复造轮子 - 如果业务强制要求正则(如前端同步校验),至少用
System.Net.IPAddress.ToString()反向标准化后再比对,而非直接匹配原始输入
空字符串、null、含空格的字符串会怎样?
IPAddress.TryParse 对 null 和空字符串直接返回 false,这是预期行为;但对首尾含空格的字符串(如 " 127.0.0.1 ")也会失败——它不做 Trim。
这点常被忽略,导致 UI 输入带空格时验证意外失败。
- 务必在调用前手动
Trim():IPAddress.TryParse(input?.Trim(), out _) - 不要依赖
Convert.ToString或隐式转换来“清理”,它们可能把null转成字符串"null",反而引入新错误 - 如果输入来自配置文件或 HTTP Header,还要注意不可见字符(如 BOM、U+00A0 不间断空格),
Trim()默认不处理,必要时需额外清洗
实际用的时候,最麻烦的往往不是“怎么写对”,而是“谁负责 Trim、谁负责判 null、谁保证不传入控制台粘贴来的带 BOM 的文本”。这些边界比协议本身更消耗调试时间。


















