今天发现C#的字符串操作是优化过的~~~

Lostinet 2002-12-17 08:19:02
例如:
string a=str1+str2+str3+str4;
将会变成:
string a=String.Concat(str1,str2,str3,str4);
来编译~~~

...全文
178 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
smilefox 2002-12-19
  • 打赏
  • 举报
回复
www.compuware.com
www.compuware-china.com

Compuware Numega Devpartner

Numega的东西应该知道吧,softice,boudschecker。。。。。
smilefox 2002-12-19
  • 打赏
  • 举报
回复
佛说:
一切众生皆有如来智慧德相,
皆因妄想执著而不能证得。

佛还说:大家该睡觉了。
7710703 2002-12-19
  • 打赏
  • 举报
回复
呵呵,不好意思,
smilefox(笑面狐):
能否告知一下你是在哪里搞到的Compuware Devpartner?
谢谢。
smilefox 2002-12-19
  • 打赏
  • 举报
回复
我也上床了,一个人。
dy_2000_abc 2002-12-19
  • 打赏
  • 举报
回复
柴门闻犬吠,风雪夜归人。同路同路
Lostinet 2002-12-19
  • 打赏
  • 举报
回复
在循环中,Contact很难用的。
所以我一般也是用StringBuilder

我睡了。
smilefox 2002-12-19
  • 打赏
  • 举报
回复
都是夜猫子。
dy_2000_abc 2002-12-19
  • 打赏
  • 举报
回复
不能吧,我觉得如果字符数是固定的话,StringBuilder怎么也不可能比Concat快,因为Concat一次就将内存分配完毕,而StringBuilder如果初次分配的内存不够的话,还要再次分配内存。可这没有太大的意义了,不是太极端(比如:StringBuilder s=new StringBuilder(1))的话,差别是可以忽略的。
smilefox 2002-12-19
  • 打赏
  • 举报
回复
看错了,qqchen79(知秋一叶)说得没错,眼花了。

双眼通红,;-(
smilefox 2002-12-19
  • 打赏
  • 举报
回复
继续讨论:

对qqchen79(知秋一叶)的如下看法,fox不敢苟同-----

">> 关于优化的说法,我个人认为主要是针对第一个例子。而编译器为string >> 其他类型 调用Concat方法的好处在于string + 值类型 这样的情况:
>> string s="a";
>> int n=1;
>> string s1=s+1;
>> 这时,值类型不用装箱了。
应该还是要装箱的,Concat有两种形式,一是接受string,一是object;C#编译器不能随便把int32转成string,只能当object,所以要装箱。如果要优化,用string s1=s+1.ToString()要好一点——这个不用装箱。"

string s="a";
int n=1;
string s1=s+1;其实这里有一个隐含的装箱的过程。

大家要注意一下,

-------------------------
每个值类型都有一个对应的隐含的引用类型,他是在值类型转换为引用类型时自动创建。不是通常的装箱。

看下面的代码:
using System;

namespace box1
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
string s1="1";
string s2="2";
string s3="3";
string s=s1+s2+s3;
string d=s+1;//这里有一个隐含的装箱

Console.WriteLine(s);
Console.WriteLine(d);
}
}
}

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 55 (0x37)
.maxstack 3
.locals init ([0] string s1,
[1] string s2,
[2] string s3,
[3] string s,
[4] string d)
IL_0000: ldstr "1"
IL_0005: stloc.0
IL_0006: ldstr "2"
IL_000b: stloc.1
IL_000c: ldstr "3"
IL_0011: stloc.2
IL_0012: ldloc.0
IL_0013: ldloc.1
IL_0014: ldloc.2
IL_0015: call string [mscorlib]System.String::Concat(string,
string,
string)
IL_001a: stloc.3
IL_001b: ldloc.3
IL_001c: ldc.i4.1
IL_001d: box [mscorlib]System.Int32
IL_0022: call string [mscorlib]System.String::Concat(object,
object)
IL_0027: stloc.s d
IL_0029: ldloc.3
IL_002a: call void [mscorlib]System.Console::WriteLine(string)
IL_002f: ldloc.s d
IL_0031: call void [mscorlib]System.Console::WriteLine(string)
IL_0036: ret
} // end of method Class1::Main


隐含的装箱在这里------------------------------
IL_001c: ldc.i4.1
IL_001d: box [mscorlib]System.Int32
IL_0022: call string [mscorlib]System.String::Concat(object,
。。。。
smilefox 2002-12-19
  • 打赏
  • 举报
回复
又有人熬通宵;-),累啊
chinchy 2002-12-19
  • 打赏
  • 举报
回复
qqchen79 2002-12-19
  • 打赏
  • 举报
回复
我还没睡。:)

>> 使用
>> string a=str1+str2+str3+str4
>> 和
>> string a=str1;
>> a+=str2;
>> a+=str3;
>> a+=str4;
这两个不一样,不光是因为Concat函数调用的次数,而且是临时对象的产生:头一个除了str1234以外没有生成多余的临时对象,而后一个每走一步就丢下一个临时对象交给GC收拾(string是immutable的,a+=b相当于string temp = a + b; a = temp;原先的a就没用了)内存的footprint很不光彩。

>> 关于优化的说法,我个人认为主要是针对第一个例子。而编译器为string >> 其他类型 调用Concat方法的好处在于string + 值类型 这样的情况:
>> string s="a";
>> int n=1;
>> string s1=s+1;
>> 这时,值类型不用装箱了。
应该还是要装箱的,Concat有两种形式,一是接受string,一是object;C#编译器不能随便把int32转成string,只能当object,所以要装箱。如果要优化,用string s1=s+1.ToString()要好一点——这个不用装箱。
dy_2000_abc 2002-12-19
  • 打赏
  • 举报
回复
知秋是对的,我写那段的时候,感觉是Concat将会象WriteLine一样,不用装箱了。看样子不能过过分依赖感觉,今天我看了一下Concat的所有重载方法,统统需要引用类型作为参数,也就是说值类型需要先装箱。
smilefox 2002-12-19
  • 打赏
  • 举报
回复
刚刚用Devpartner测了一下:

string s=s1+s2+s3;//执行时间1.2819毫秒

string d=s+1;//这里有一个隐含的装箱
执行时间61.0279毫秒
看来装箱操作对性能影响较为明显。

机器配置:PIII650 256M DELL Latitude笔记本电脑
lixigang 2002-12-18
  • 打赏
  • 举报
回复
真长见识
Lostinet 2002-12-18
  • 打赏
  • 举报
回复
chenbinghui(阿炳):
StringBuilder是快,但只有极少应用是才是100倍或以上。

static public string String::Contact(...)是最快的。


smilefox 2002-12-18
  • 打赏
  • 举报
回复
谢谢dy_2000_abc(芝麻开门) Lostinet(迷失网络) 两位的精彩解说。
楼主的例子确实没问题--------------------
"例如:
string a=str1+str2+str3+str4;
将会变成:
string a=String.Concat(str1,str2,str3,str4);
来编译~~~" -----------------------

可能大家误认为str1~4不是常量字符串"111","222",....

而是string str1="1111"......
string str4+=..诸如此类,这样的话就会是垃圾了。

dy_2000_abc(芝麻开门)代码已经说明了问题,看来我有一点说错了。

说到垃圾代码,刚学C#时我经常写那种代码。我想这是每个程序员的成长过程中肯定会经历的,不管他是用C/C++/C#/Delphi,还是Java/VB/ASM等等。关键在于能不断的研究和实践,这一点很佩服dy_2000_abc(芝麻开门)兄,向你学习!;-)




Lostinet 2002-12-18
  • 打赏
  • 举报
回复
楼上的,你的例子太极端了.
统计应该是这样做的:
当然可以指定StringBuilder的capacity,这样可以快1/5左右。

using System;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

namespace L
{
public class L
{
static void Test0()
{
DateTime dt1=DateTime.Now;
for(int count=0;count<666666;count++)
{
string str1="a";
string str2="b";
string str3="c";
string str4="d";
string res=str1+str2+str3+str4;
}
DateTime dt2=DateTime.Now;
Console.WriteLine( (dt2-dt1).TotalMilliseconds );

}
static void Test1()
{
DateTime dt1=DateTime.Now;
for(int count=0;count<666666;count++)
{
string[] strs=new string[4];
for(int i=0;i<4;i++)
{
strs[i]="a";
}
string res=String.Concat(strs);
}
DateTime dt2=DateTime.Now;
Console.WriteLine( (dt2-dt1).TotalMilliseconds );
}
static void Test2()
{
DateTime dt1=DateTime.Now;
for(int count=0;count<666666;count++)
{
StringBuilder sb=new StringBuilder();
for(int i=0;i<4;i++)
{
sb.Append("a");
}
string res=sb.ToString();
}
DateTime dt2=DateTime.Now;
Console.WriteLine( (dt2-dt1).TotalMilliseconds );
}
static void Main()
{
Test0();
Console.WriteLine();
Test1();
Console.WriteLine();
Test2();
}
}
}
dy_2000_abc 2002-12-18
  • 打赏
  • 举报
回复
漏了一段代码
using System;

namespace abc
{
public class a
{
static void Main()
{
string s1="1";
string s2="2";
string s3="3";
string s4="3";
string s5="3";
string s6="3";
string s7="3";
string s=s1+s2+s3+s4+s5+s6+s7;
Console.WriteLine(s);
}
}
}
上面代码的IL如下:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 108 (0x6c)
.maxstack 3
.locals init (string V_0,
string V_1,
string V_2,
string V_3,
string V_4,
string V_5,
string V_6,
string V_7,
string[] V_8)
IL_0000: ldstr "1"
IL_0005: stloc.0
IL_0006: ldstr "2"
IL_000b: stloc.1
IL_000c: ldstr "3"
IL_0011: stloc.2
IL_0012: ldstr "3"
IL_0017: stloc.3
IL_0018: ldstr "3"
IL_001d: stloc.s V_4
IL_001f: ldstr "3"
IL_0024: stloc.s V_5
IL_0026: ldstr "3"
IL_002b: stloc.s V_6
IL_002d: ldc.i4.7
IL_002e: newarr [mscorlib]System.String
IL_0033: stloc.s V_8
IL_0035: ldloc.s V_8
IL_0037: ldc.i4.0
IL_0038: ldloc.0
IL_0039: stelem.ref
IL_003a: ldloc.s V_8
IL_003c: ldc.i4.1
IL_003d: ldloc.1
IL_003e: stelem.ref
IL_003f: ldloc.s V_8
IL_0041: ldc.i4.2
IL_0042: ldloc.2
IL_0043: stelem.ref
IL_0044: ldloc.s V_8
IL_0046: ldc.i4.3
IL_0047: ldloc.3
IL_0048: stelem.ref
IL_0049: ldloc.s V_8
IL_004b: ldc.i4.4
IL_004c: ldloc.s V_4
IL_004e: stelem.ref
IL_004f: ldloc.s V_8
IL_0051: ldc.i4.5
IL_0052: ldloc.s V_5
IL_0054: stelem.ref
IL_0055: ldloc.s V_8
IL_0057: ldc.i4.6
IL_0058: ldloc.s V_6
IL_005a: stelem.ref
IL_005b: ldloc.s V_8
IL_005d: call string [mscorlib]System.String::Concat(string[])
IL_0062: stloc.s V_7
IL_0064: ldloc.s V_7
IL_0066: call void [mscorlib]System.Console::WriteLine(string)
IL_006b: ret
} // end of method a::Main

代码好像很多,其实意思很简单
加载更多回复(10)

110,545

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧