c#

位置:IT落伍者 >> c# >> 浏览文章

在.NET程序中正确使用String类型[2]


发布日期:2023年03月24日
 
在.NET程序中正确使用String类型[2]
再看第()段代码生成的指令

locals init ([] string s)

IL_: nop

IL_: ldstr abcd

IL_: stloc

IL_: ret

可以很清楚地看到第()段代码将导致String类的Concat()方法被调用(实现字串加法运算)对于第()段代码由于C#编译器聪明地在编译时直接将两个字串合并为一个字串字面量所以程序运行时CLR只调用一次ldstr指令就完成了所有工作其执行速度谁快就不言而喻了!

避免使用加法运算符连接不同类型的数据

请看以下代码

String str = += + ;

ConsoleWriteline(str);

生成的MSIL指令为

maxstack

locals init ([] string str)

IL_: nop

IL_: ldstr +=

IL_: ldci xc

IL_b: box [mscorlib]SystemInt

IL_: call string [mscorlib]SystemString::Concat(object

object)

IL_: stloc

IL_: ldloc

IL_: call void [mscorlib]SystemConsole::WriteLine(string)

IL_c: nop

IL_d: ret

可以清晰地看到这两句C#代码不仅导致了String类的Concat()方法被调用(IL_而且还引发了装箱操作(IL_b)!

Concat()方法会导致CLR为新字串分配内存空间而装箱操作不仅要分配内存还需要创建一个匿名对象对象创建之后还必须有一个数据复制的过程代价不菲!

改为以下代码

String str = +=;

ConsoleWrite(str);

ConsoleWriteLine();

生成的MSIL指令为

maxstack

locals init ([] string str)

IL_: nop

IL_: ldstr +=

IL_: stloc

IL_: ldloc

IL_: call void [mscorlib]SystemConsole::Write(string)

IL_d: nop

IL_e: ldci xc

IL_: call void [mscorlib]SystemConsole::WriteLine(int)

IL_: nop

IL_: ret

可以看到虽然多了一次方法调用(ConsoleWrite)方法但却避免了复杂的装箱操作也避免了调用StringConcat()方法对内存的频繁分配操作性能更好

.在循环中使用StringBuilder代替String实现字串连接

在某些场合需要动态地将多个子串连接成一个大字串比如许多复杂的SQL命令都是通过循环语句生成的这时应避免使用String类的加法运算符举个简单的实例

String str =;

for (int i = ; i <= ; i++)

{

str += i;

if(i<)

str += +;

}

上述代码将生成一个字串++…+

有了前面的知识读者一定知道这将导致进行次装箱操作次字串内存分配操作(由StringConcat()方法引发)由于生成的MSIL指令太长此处不再列出请读者自行用ildasmexe工具查看上述代码生成的MSIL指令

改为以下代码程序性能会好很多

//预先分配K的内存空间

StringBuilder sb = new StringBuilder();

for (int i = ; i <= ; i++)

{

sbAppend(i);

if(i<)

sbAppend(+);

}

String result = sbToString();

通过使用ildasmexe工具查看生成的MSIL代码发现虽然上述代码生成的MSIL指令比前面多了但却避免了耗时的装箱操作而且内存分配的次数也少了很多当循环的次数很大时两段代码的运行性能差异很大

[] []

               

上一篇:.Net中处理Word 2007文档的一种方法

下一篇:在.NET程序中正确使用String类型[1]