温故知新,CSharp遇见字符串比较(String Comparison),更佳科学的比较字符串

背景

在C#中,我们经常会遇到需要比较字符串的场景,有时候甚至因为外部输入的不确定性,我们需要忽略大小写来进行比较,以达到判断业务的述求。

image

对字符串用法的建议

使用.NET进行开发时,请遵循以下简要建议比较字符串:

  • 使用为字符串操作显式指定字符串比较规则的重载。通常情况下,这涉及调用具有StringComparison类型的参数的方法重载。
  • 使用StringComparison.OrdinalStringComparison.OrdinalIgnoreCase进行比较,并以此作为匹配区域性不明确的字符串的安全默认设置。
  • 将比较与StringComparison.OrdinalStringComparison.OrdinalIgnoreCase配合使用,以获得更好的性能。
  • 向用户显示输出时,使用基于StringComparison.CurrentCulture的字符串操作。
  • 当进行与语言(例如,符号)无关的比较时,使用非语言的StringComparison.OrdinalStringComparison.OrdinalIgnoreCase值,而不使用基于CultureInfo.InvariantCulture的字符串操作。
  • 在规范化要比较的字符串时,使用String.ToUpperInvariant方法而非String.ToLowerInvariant方法。
  • 使用String.Equals方法的重载来测试两个字符串是否相等。
  • 使用String.CompareString.CompareTo方法可对字符串进行排序,而不是检查字符串是否相等。
  • 在用户界面,使用区分区域性的格式显示非字符串数据,如数字和日期。使用格式以固定区域性使非字符串数据显示为字符串形式。

比较字符串时,请避免采用以下做法:

  • 不要使用未显式或隐式为字符串操作指定字符串比较规则的重载。
  • 在大多数情况下,不要使用基于StringComparison.InvariantCulture的字符串操作。其中的一个少数例外情况是,保存在语言上有意义但区域性不明确的数据。
  • 不要使用String.CompareCompareTo方法的重载和用于确定两个字符串是否相等的返回值为0的测试。

显式指定字符串比较

重载.NET中大部分字符串操作方法。通常,一个或多个重载会接受默认设置,然而其他重载则不接受默认设置,而是定义比较或操作字符串的精确方式。大多数不依赖于默认设置的方法都包括StringComparison类型的参数,该参数是按区域性和大小写为字符串比较显式指定规则的枚举。

StringComparison枚举成员

StringComparison 成员 描述
CurrentCulture 使用当前区域性执行区分大小写的比较。
CurrentCultureIgnoreCase 使用当前区域性执行不区分大小写的比较。
InvariantCulture 使用固定区域性执行区分大小写的比较。
InvariantCultureIgnoreCase 使用固定区域性执行不区分大小写的比较。
Ordinal 执行序号比较。
OrdinalIgnoreCase 执行不区分大小写的序号比较。

例如,IndexOf方法(它返回String对象中与某字符或字符串匹配的子字符串的索引)具有九种重载:

  • 默认情况下,IndexOf(Char),IndexOf(Char,Int32)IndexOf(Char,Int32,Int32)对字符串中的字符执行序号(区分大小写但不区分区域性的)搜索。
  • 默认情况下,IndexOf(String),IndexOf(String,Int32)IndexOf(String,Int32,Int32)对字符串中的子字符串执行区分大小写且区分区域性的搜索。
  • IndexOf(String,StringComparison)IndexOf(String,Int32,StringComparison)IndexOf(String,Int32,Int32,StringComparison),其中包括StringComparison类型的参数,该类型允许指定比较形式。

我们建议选择不使用默认值的重载,原因如下:

  • 具有默认参数的一些重载(在字符串实例中搜索Char的重载)执行序号比较,而其他重载(在字符串实例中搜索字符串的重载)执行的是区分区域性的比较。要记住哪种方法使用哪个默认值并非易事,并很容易混淆重载。

  • 依赖于方法调用默认值的代码的意图并不清楚。在下面依赖于默认值的示例中,很难了解开发人员对两个字符串的实际意图是执行序号比较还是语言比较,或者protocol和“http”之间存在的大小写差异是否会导致相等性测试返回false类型的参数的方法重载。

string protocol = GetProtocol(url);
if (String.Equals(protocol, "http")) {
   // ...Code to handle HTTP protocol.
}
else {
   throw new InvalidOperationException();
}

一般情况下,我们建议调用不依赖于默认设置的方法,因为这会明确代码的意图。这进而使代码更具可读性且更易于调试和维护。下面的示例解决了前面示例中提出的问题。使用序号比较并且忽略大小写差异。

string protocol = GetProtocol(url);
if (String.Equals(protocol, "http", StringComparison.OrdinalIgnoreCase)) {
   // ...Code to handle HTTP protocol.
}
else {
   throw new InvalidOperationException();
}

参考

posted @ 2021-05-25 12:32  TaylorShi  阅读(913)  评论(0编辑  收藏  举报