.Net中的字符串是被谈论最多的话题,这里也进行一些总结,供以后参考。
主要内容:
- 字符串的不可变性和字符串留用
- 语言文化
- 格式化器
1. 字符串的不可变性和字符串留用
字符串(string)在.Net中是一个特殊的类。
.Net中的字符串是不可变的(immutable)。也就是说,字符串已经创建就不能更改,变长,变短,修改字符都不行。
对字符串进行的任何操作都不能改变原字符串,只会生成新的字符串。
由于String是不可变的,我们在使用大量的字符串拼接的时候不宜使用 【+】运算符,比如
1
|
"A"
+
"B"
+
"C"
|
而是可以使用StringBuilder这个类,
1
2
3
4
|
StringBuilder sb =
new
StringBuilder();
sb.Append(
"A"
);
sb.Append(
"B"
);
sb.Append(
"C"
);
|
这样可以避免在内存中不断生成新的string对象。
StringBuilder的工作原理大致是这样的:
内部维护一个字符数组,并且有一个初始容量。
新的字符串都加入到这个数组中。
当加入的字符超过容量时,就重新new一个更大的数组,并将原先的数组内容拷入新数组中。
将原有的数组进行垃圾回收,新的字符串加入到使用新的字符数组中。
StringBuilder的ToString方法见字符数组转换为一个String输出。
为了提高字符串的性能,.Net中对已有的字符串进行了留用,使得再次使用相同的字符串时不用重新申请内存。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
using
System;
public
class
CLRviaCSharp_16
{
static
void
Main(
string
[] args)
{
string
s1 =
"Hello"
;
string
s2 =
"Hello"
;
// 应该为 False
Console.WriteLine(
object
.ReferenceEquals(s1, s2));
s1 = String.Intern(
"Hello"
);
s2 = String.Intern(
"Hello"
);
// 显示 True
Console.WriteLine(
object
.ReferenceEquals(s1, s2));
Console.ReadKey(
true
);
}
}
|
第一次的执行结果应该为False,但是CLR在编译时默认进行了留用,所以2次结果都是True
我们如果要使用字符串留用的话,一定要明确使用String.Intern,否则CLR版本变更后有可能不默认进行字符串留用。
那样,运行结果就变了。
2. 语言文化
字符串的语言文化在使用中很少涉及,但是如果不注意的话,可能会遇到意料之外的错误。
如以下中文和日语的比较,用不同的语言文化,比较结果就不同。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
using
System;
using
System.Globalization;
public
class
CLRviaCSharp_16
{
static
void
Main(
string
[] args)
{
string
s1 =
"中文"
;
string
s2 =
"日本語"
;
CompareInfo compareInfo = CompareInfo.GetCompareInfo(
"ja-JP"
);
Console.WriteLine(compareInfo.Compare(s1, s2));
compareInfo = CompareInfo.GetCompareInfo(
"zh-CN"
);
Console.WriteLine(compareInfo.Compare(s1, s2));
Console.ReadKey(
true
);
}
}
|
在不同语言之间进行字符串比较需要注意语言文化对结果的影响。
3. 格式化器
通过格式化器,可以将字符串按照一定的格式输出,在打印或者log输出上会很有用。
实现自定义的格式化器需要继承IFormatProvider, ICustomFormatter两个接口。
下面通过例子演示如何通过定制格式化器来调整打印输出的。
例子很简单,依次输出字符串,
如果字符串长度大于4,则截断尾部,只输出4个字符。
如果字符串长度小于4,则在尾部补充【*】,使长度达到4。
如果字符串长度等于4,则直接输出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
using
System;
public
class
CLRviaCSharp_16
{
static
void
Main(
string
[] args)
{
string
[] strs =
new
string
[] {
"sadfasdf"
,
"dgdgfdsds"
,
"ggh"
,
"w"
,
"abcd"
};
foreach
(
var
str
in
strs)
{
Console.WriteLine(
string
.Format(
new
FormatPrint(),
"{0}"
, str));
}
Console.ReadKey(
true
);
}
}
internal
class
FormatPrint : IFormatProvider, ICustomFormatter
{
#region IFormatProvider Members
public
object
GetFormat(Type formatType)
{
if
(formatType ==
typeof
(ICustomFormatter))
return
this
;
else
return
null
;
}
#endregion
#region ICustomFormatter Members
public
string
Format(
string
format,
object
arg, IFormatProvider formatProvider)
{
string
s;
IFormattable formattable = arg
as
IFormattable;
if
(formattable ==
null
)
s = arg.ToString();
else
s = formattable.ToString(format, formatProvider);
// 开始处理长度
if
(s.Length > 4)
return
s.Substring(0, 4);
else
if
(s.Length == 4)
return
s;
for
(
int
i = s.Length; i < 4; i++)
s +=
"*"
;
return
s;
}
#endregion
}
|