版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jingangxin666/article/details/80786868
MSDN中对字符串使用做法的建议:
本文做一些使用方法的记录和补充.
一. 对字符串用法的建议
1. 当进行字符串操作时, 显式指定字符串比较规则, 即调用具有StringComparison
类型的参数的方法重载.
原因如下:
- 具有默认参数的一些重载执行序号比较, 而其他重载执行的是区分区域性的比较. 要记住哪种方法使用哪个默认比较规则并非易事,并很容易混淆重载(例如
String.IndexOf
的九种重载方法) - 依赖于所调用的方法的默认值, 这样的代码意图并不明确
- 在下面的例子中, 很难知道开发者是想要进行二进制还是语言性的排序, 或者该相等性测试是否考虑了大小写的差异
string protocol = GetProtocol(url);
if (String.Equals(protocol, "http")) {
// ...Code to handle HTTP protocol.
}
else {
throw new InvalidOperationException();
}
2. 字典排序和二进制排序的不同(来源):
- 二进制排序是根据针对每个字符定义的位模式来排序与比较.
- 二进制排序方式区分大小写, 亦即小写比大写优先, 且区分腔调字. 这是最快的排序方式.
- 因为特定语言中字码页中位模式可能与字典规则所定义的顺序不同, 所以若将字符依二进制排序, 有时候结果可能不是使用该语系的使用者所预期的顺序.
3. 何时使用StringComparison.Ordinal
或 StringComparison.OrdinalIgnoreCase
(不区分地域性的格式):
- 进行区域性不明确的字符串比较时
- 获得更好的性能
- 进行与语言无关(例如, 符号)的比较时.
4. 何时使用区分地域性的格式:
- 需要向用户显示输出结果
- 在用户界面, 显示非字符串数据, 例如数字或日期
- 使非字符串数据固定地以字符串形式显示
5. DOs
- 使用
String.Compare
和String.CompareTo
方法来对字符串进行排序, 不要用来检查字符串是否相等 - 使用
String.Equals
的一个重载方法来测试两个字符串是否相等 - 在规范化要比较的字符串时,使用
String.ToUpperInvariant
方法而不是String.ToLowerInvariant
方法。
6. DON’Ts
- 在进行字符串操作时, 不要使用未显示或隐式指定字符串比较规则的重载方法
- 在大多数情况下, 不要使用基于
StringComparison.InvariantCulture
的字符串操作. 一个少数例外情况是, 保存在语言上有意义但区域性不明确的数据 - 不要使用区分区域性格式字符串形式来保存数值数据或日期和时间数据
- 判断两个字符串是否相等时, 不要使用以下方法:
String.Compare
String.CompareTo
- 返回值为0的测试
二. 显示地指定字符串比较规则
StringComparison
类型的是按区域性和大小写为字符串比较显式指定规则的枚举类型. 下表描述 StringComparison
枚举成员.
StringComparison 成员 | 描述 |
---|---|
CurrentCulture | 使用当前区域性执行区分大小写的比较。 |
CurrentCultureIgnoreCase | 使用当前区域性执行不区分大小写的比较。 |
InvariantCulture | 使用固定区域性执行区分大小写的比较。 |
InvariantCultureIgnoreCase | 使用固定区域性执行不区分大小写的比较。 |
Ordinal | 执行二进制比较。 |
OrdinalIgnoreCase | 执行不区分大小写的二进制比较。 |
三. .NET 中的常见字符串比较方法
String.Compare
- 确认是否使用区域性比较
- 通常指定
StringComparison.Ordinal
进行比较 CompareOptions
枚举类型也提供大量匹配选项( 序号、忽略空白、忽略假名类型等 )
1. String.CompareTo
- 此方法当前不提供指定
StringComparison
类型的重载. 通常可以将此方法转换为建议的String.Compare(String, String, StringComparison)
形式. 举例如下: - 定义
FileName
类,继承IComparable
接口并实现String.CompareTo
方法. 其类构造函数包括StringComparer
参数. 然后此StringComparer
对象将用于FileName.CompareTo
方法.
using System;
public class FileName : IComparable
{
string fname;
StringComparer comparer;
public FileName(string name, StringComparer comparer)
{
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
this.fname = name;
if (comparer != null)
this.comparer = comparer;
else
this.comparer = StringComparer.OrdinalIgnoreCase;
}
public string Name
{
get { return fname; }
}
public int CompareTo(object obj)
{
if (obj == null) return 1;
if (! (obj is FileName))
return comparer.Compare(this.fname, obj.ToString());
else
return comparer.Compare(this.fname, ((FileName) obj).Name);
}
}
2. String.Equals
- 测试字符串相等性, 可以采用以下方法
Equals
方法重载- 静态相等操作符
==
- 重载方法和操作符默认使用二进制比较
- 仍然建议调用显示指定
StringComparison
类型的重载, 即使想要使用二进制比较. 这将更轻松地搜索特定字符串解释的代码
3. String.ToUpper 和 String.ToLower
- 将字符串强制为大写或小写形式, 通常是用在不考虑大小写的情况下比较字符串时的小型规范化. 谨慎使用这些方法, 如果是这种情况, 可以考虑使用不区分大小写的比较
- 还可以使用
String.ToUpperInvariant
和String.ToLowerInvariant
方法.ToUpperInvariant
是规范化大小写的标准方式
4. Char.ToUpper 和 Char.ToLower
- 这些方法的工作原理类似于上述的
String.ToUpper
和String.ToLower
方法
5. String.StartsWith 和 String.EndsWith
- 默认情况下,这两种方法执行区分区域性的比较
- 注意在比较文件后缀的时候, 大部分情况是忽略大小写的后缀. 例如
*.FBX
和*.fbx
6. String.IndexOf 和 String.LastIndexOf
- 如果调用
String.IndexOf(String)
或String.LastIndexOf(String)
方法并向其传递一个字符串以在当前实例中查找, 那么我们建议调用显式指定StringComparison
类型的重载 - 包括 Char 参数的重载不允许指定
StringComparison
类型.
四. 间接执行字符串比较的方法
Array.Sort 和 Array.BinarySearch
Array.Sort
默认使用的比较规则为StringComparison.CurrentCulture
,Array.BinarySearch
方法假定array中的元素已经排好序了, 再对array进行二进制搜索- 如果要
Array.Sort
和Array.BinarySearch
一起使用, 应该显示地指定比较规则. 否则可能会出现更改了区域性, 造成二进制搜索失败
// 错误
string []storedNames;
public void StoreNames(string [] names)
{
int index = 0;
storedNames = new string[names.Length];
foreach (string name in names)
{
this.storedNames[index++] = name;
}
Array.Sort(names); // Line A.
}
public bool DoesNameExist(string name)
{
return (Array.BinarySearch(this.storedNames, name) >= 0); // Line B.
}
建议Line A和Line B使用相同的二进制比较方法(不区分区域性)进行数组的排序和搜索. 如下例:
// 正确
string []storedNames;
public void StoreNames(string [] names)
{
int index = 0;
storedNames = new string[names.Length];
foreach (string name in names)
{
this.storedNames[index++] = name;
}
Array.Sort(names, StringComparer.Ordinal); // Line A.
}
public bool DoesNameExist(string name)
{
return (Array.BinarySearch(this.storedNames, name, StringComparer.Ordinal) >= 0); // Line B.
}
如果此数据是固定的并跨区域性移动, 并且使用排序来向用户显示此数据 ,则可以考虑使用 StringComparison.InvariantCulture
,其操作可获得更好的用户输出且不受区域性更改的影响. 下面的示例修改了前面两个示例, 使用固定区域性对数组进行排序和搜索
// 正确
string []storedNames;
public void StoreNames(string [] names)
{
int index = 0;
storedNames = new string[names.Length];
foreach (string name in names)
{
this.storedNames[index++] = name;
}
Array.Sort(names, StringComparer.InvariantCulture); // Line A.
}
public bool DoesNameExist(string name)
{
return (Array.BinarySearch(this.storedNames, name, StringComparer.InvariantCulture) >= 0); // Line B.
}