今天看到了你真的了解.NET中的String吗? 的文章,写的很不错,对string不错的说明,但是有几点我想补充一下,一旦你的string在堆中创建后,其在内存中都是以const存在,任何的修改都会使其被重新创建为新的string,而指向以前的string的引用将会指向这个新的string!!测试1:看下面的代码:
1
string
s
=
"
1
"
;
2
Console.WriteLine( String.IsInterned(s)
!=
null
);//这里输出true
这个代码很简单,声名一个string s并且赋予"1",这个时候s在CLR的内置池中表示为引用,再来看下面的代码:
1
string
s
=
"
1
"
;
//
初始化string
2
Console.WriteLine( String.IsInterned(s)
!=
null
);//这里输出true
3
4
s
+=
"
2
"
;
//
追加string
5
Console.WriteLine( String.IsInterned(s)
!=
null
);//这里输出false
6
这个时候你再看输出的结果:第一次的s="1"的时候,s在内置池中,但是当你修改了s的值之后,它已经不在内置池中!!如果你需要将s再次放置到内置池中,可以这么做:
1
string
s
=
"
1
"
;
//
初始化string
2
Console.WriteLine( String.IsInterned(s)
!=
null
);
//
输出true
3
4
s
+=
"
2
"
;
//
追加string
5
Console.WriteLine( String.IsInterned(s)
!=
null
);
//
输出false
6
7
String.Intern(s);
//
重新设置为引用
8
Console.WriteLine( String.IsInterned(s)
!=
null
);
//
这个时候依然输出为true
测试2:看下面的测试代码:
1
string
a
=
"
1
"
;
//
第一次内置string
2
a
+=
"
2
"
;
//
第二次分配,赋值第一次的1到新的地址中,需重新分配内存
3
a
+=
"
3
"
;
//
第三次分配,赋值前两次的1,2到新的地址中,需重新分配内存
4
a
+=
"
4
"
;
//
第四次分配,赋值前三次的1,2,3到新的地址中,需重新分配内存
5
6
/**/
/* 使用IL反编译后看的结果 7 * 8 * .method private hidebysig static void Main(string[] args) cil managed 9{10 .entrypoint11 .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 12 // 代码大小 43 (0x2b)13 .maxstack 214 .locals init ([0] string a)15 IL_0000: ldstr "1"16 IL_0005: stloc.017 IL_0006: ldloc.018 IL_0007: ldstr "2"19 IL_000c: call string [mscorlib]System.String::Concat(string,//注意这里,复制一次20 string)21 IL_0011: stloc.022 IL_0012: ldloc.023 IL_0013: ldstr "3"24 IL_0018: call string [mscorlib]System.String::Concat(string,//复制二次25 string)26 IL_001d: stloc.027 IL_001e: ldloc.028 IL_001f: ldstr "4"29 IL_0024: call string [mscorlib]System.String::Concat(string,//复制第三次30 string)31 IL_0029: stloc.032 IL_002a: ret33} // end of method Class1::Main34 * 35
相信通过上面的代码和反编译后的结果,大家可以看的很清楚,string如何被分配,而在你重新修改string的时候,是如何工作..既然发现了问题,当然也可以解决问题所在..解决和优化的办法很多,我只简单的列出几种,第一种,使用string[]数组来代替..看下面代码:
1
string
[] Arr1
=
new
string
[
4
];
//
声名需要内置4个string
2
Arr1[
0
]
=
"
1
"
;
//
内置了1
3
Arr1[
1
]
=
"
2
"
;
//
内置了2
4
Arr1[
2
]
=
"
3
"
;
//
内置了3
5
Arr1[
3
]
=
"
4
"
;
//
内置了4
6
/**/
/*数组赋值后,在IL反编译后的表现 7 * 8 * 9 *.method private hidebysig static void Main(string[] args) cil managed10{11 .entrypoint12 .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 13 // 代码大小 40 (0x28)14 .maxstack 315 .locals init ([0] string[] Arr1)16 IL_0000: ldc.i4.417 IL_0001: newarr [mscorlib]System.String18 IL_0006: stloc.019 IL_0007: ldloc.020 IL_0008: ldc.i4.021 IL_0009: ldstr "1"22 IL_000e: stelem.ref23 IL_000f: ldloc.024 IL_0010: ldc.i4.125 IL_0011: ldstr "2"26 IL_0016: stelem.ref27 IL_0017: ldloc.028 IL_0018: ldc.i4.229 IL_0019: ldstr "3"30 IL_001e: stelem.ref31 IL_001f: ldloc.032 IL_0020: ldc.i4.333 IL_0021: ldstr "4"34 IL_0026: stelem.ref35 IL_0027: ret36} // end of method Class1::Main37 * 38 * */
看看上面的代码,我想很明白,string[]是如何工作的了吧??可以这么理解:每个数组的子项都是一个被内置的string!!第二种解决办法是char[],如果你知道你的字符串大小,可以这么写char[] c = new char[4]{'1','2','3','4'};这个做法在C/C++中是很不错的,但是在C#似乎用的不多,而且用起来也比较麻烦.因为它不能想C/C++这样: char[] c = {"1234"};不过我依然在做一个加密/解密类的时候用了char[]!!最后一种也是最常用的:StringBuilder,既然string有重新分配地址的副作用.所以微软也为我们提供了StringBuilder来解决这个问题..限于篇幅,StringBuilder我将放在下个篇幅中详细介绍它的实现和技巧,发布后我会在这里做连接..StringBuilder的实现与技巧
转载请注明原文地址: https://ibbs.8miu.com/read-25990.html