up,
StringBuilder sb=new StringBuilder();
sb.Append(str1);
sb.Append(str2);
sb.Append(str3);
...
据说速度比str1+str2+str3快100倍!

解决方案 »

  1.   

    chenbinghui(阿炳):
    StringBuilder是快,但只有极少应用是才是100倍或以上。static public string String::Contact(...)是最快的。
      

  2.   

    长字符串的连接建议用stringbuillder类,
    string是引用类型,在多个字符串加时,程序要为每一个string的实例分配空间,而stringbuillder是值类型,内存在堆栈分配,而且不像string一样有多个实例,它是微软专门用来对付字符串相加的。下面这种方法在大规模的应用
    是的性能表现明显比不上stringbuillder---
    string a=str1+str2+str3+str4;你可以在MSDN中查找一下,看看有没有
    string a=str1
    a+=str3;
    a+=str2;....
      

  3.   

    楼上:
    单纯连接4个字符串。
    string a=str1+str2+str3+str4;最快使用
    StringBuilder

    string a=str1;
    a+=str2;
    a+=str3;
    a+=str4;到底是谁我还不清楚。String::Contact的一个重载的代码如下:
    public static string Concat(string str0, string str1, string str2, string str3) {
    int local0;
    string local1; if (str0 == null && str1 == null)
    if (str2 == null && str3 == null)
    return String.Empty;
    if (str0 == null)
    str0 = String.Empty;
    if (str1 == null)
    str1 = String.Empty;
    if (str2 == null)
    str2 = String.Empty;
    if (str3 == null)
    str3 = String.Empty;
    local0 = str0.Length + str1.Length + str2.Length + str3.Length;
    local1 = String.FastAllocateString(local0);
    String.FillStringChecked(local1, 0, str0);
    String.FillStringChecked(local1, str0.Length, str1);
    String.FillStringChecked(local1, str0.Length + str1.Length, str2);
    String.FillStringChecked(local1, str0.Length + str1.Length + str2.Length, str3);
    return local1;
    }
      

  4.   

    string a=str1+str2+str3+str4和
    string a=str1;
    a+=str2;
    a+=str3;
    a+=str4;
    是一样的,都要生成同样多的string实例,即内存分配是一样的.在微软的MSDN里是找不出这样的代码的。为什么有了一个string,还要做一个stringbuilder,你想一想吧,上面已经说得很清楚拉。另外,在今年获奖的.NET测试工具中,排在首位的Compuware Devpartner里有一个代码规则检查器,就对这种代码明令禁止,
    意思就是,在代码的性能问题上,"不因善小而不为,勿以恶小而为之。"
    说得严重一点,那是垃圾代码。
      

  5.   

    我晕,.
    你没有试过xxx=xxx+"111"+xxx2+"222"+xxx3+"xxx3"..等情况?
    你都是用StringBuilder的?你都不写垃圾代码的?那如果你认为
    string a=str1+str2+str3+str4和
    string a=str1;
    a+=str2;
    a+=str3;
    a+=str4;
    是一样的,
    那么请你解释一下,,
    为什么string str="it's "+new Object();
    能够编译通过?
      

  6.   

    我也来凑个热闹请大家看看下面这个例子:
    using System;namespace abc
    {
    public class a
    {
    static void Main()
    {
    string s="1"+"2"+"3";
    Console.WriteLine(s);
    }
    }
    }
    它的IL代码是:
    .method private hidebysig static void  Main() cil managed
    {
      .entrypoint
      // Code size       13 (0xd)
      .maxstack  1
      .locals init (string V_0)
      IL_0000:  ldstr      "123"
      IL_0005:  stloc.0
      IL_0006:  ldloc.0
      IL_0007:  call       void [mscorlib]System.Console::WriteLine(string)
      IL_000c:  ret
    } // end of method a::Main       在这里我们看到这么一句: ldstr      "123",String 是引用类型,可它却没有newobj指令,这说明CLR构造String与其他的对象不一样。还有,不用我说你们都看到了:为什么是“123”,原因是编译器在编译时将它们合并成一个字符串放到了程序集的元数据中(仅限于文字字符)。这样,运行时CLR直接将它们取出来用就OK了,不用再“分别取出来,重新分配内存,复制数据“。关于这个问题:
    string a=str1+str2+str3+str4和
    string a=str1;
    a+=str2;
    a+=str3;
    a+=str4;
    是一样的,我的认为是:它们是不一样的,
    请看这个例子:
    using System;namespace abc
    {
    public class a
    {
    static void Main()
    {
    string s1="1";
    string s2="2";
    string s3="3";
    string s=s1+s2+s3;
    Console.WriteLine(s);
    }
    }
    }
    它的IL代码是:
    .method private hidebysig static void  Main() cil managed
    {
      .entrypoint
      // Code size       34 (0x22)
      .maxstack  3
      .locals init (string V_0,
               string V_1,
               string V_2,
               string V_3)
      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:  call       void [mscorlib]System.Console::WriteLine(string)
      IL_0021:  ret
    } // end of method a::Main这里我们关心的是这一句:System.String::Concat(string, string,string)
    这一句的源代码上面给出来了,它实现分配一块内存,然后将s1,s2,s3的内容复制过去。
    再请看:
    .method private hidebysig static void  Main() cil managed
    {
      .entrypoint
      // Code size       55 (0x37)
      .maxstack  2
      .locals init (string V_0,
               string V_1,
               string V_2,
               string V_3)
      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      ""
      IL_0017:  stloc.3
      IL_0018:  ldloc.3
      IL_0019:  ldloc.0
      IL_001a:  call       string [mscorlib]System.String::Concat(string,
                                                                  string)
      IL_001f:  stloc.3
      IL_0020:  ldloc.3
      IL_0021:  ldloc.1
      IL_0022:  call       string [mscorlib]System.String::Concat(string,
                                                                  string)
      IL_0027:  stloc.3
      IL_0028:  ldloc.3
      IL_0029:  ldloc.2
      IL_002a:  call       string [mscorlib]System.String::Concat(string,
                                                                  string)
      IL_002f:  stloc.3
      IL_0030:  ldloc.3
      IL_0031:  call       void [mscorlib]System.Console::WriteLine(string)
      IL_0036:  ret
    } // end of method a::Mainstring a=str1+str2+str3+str4只分配一次内存,而后者的代码需要分配三次内存。
    关于为什么string str="it's "+new Object();能够编译通过?正是因为编译器会为它调用了String的Concat静态方法关于优化的说法,我个人认为主要是针对第一个例子。而编译器为string + 其他类型 调用Concat方法的好处在于string + 值类型  这样的情况:
    string s="a";
    int n=1;
    string s1=s+1;
    这时,值类型不用装箱了。
      

  7.   

    这是比较结果:
    using System;
    namespace abc
    {
    public class a
    {
    static void Main()
    {
    DateTime t1=DateTime.Now;
    string[] s=new string[50000];
    for (int i=0;i<50000;i++)
    {
    s[i]="a";
    }
    String.Concat(s);
    DateTime t2=DateTime.Now;
    Console.WriteLine(t2-t1);
    }
    }
    }
    运行结果:00:00:00.0100144
    using System;
    namespace abc
    {
    public class a
    {
    static void Main()
    {
    DateTime t1=DateTime.Now;
    string[] s=new string[50000];
    for (int i=0;i<50000;i++)
    {
    s[i]="a";
    }
    String.Concat(s);
    DateTime t2=DateTime.Now;
    Console.WriteLine(t2-t1);
    }
    }
    }
    运行结果:00:00:27.8099888
    相差确实很大!
    using System;
    using System.Text;
    namespace abc
    {
    public class a
    {
    static void Main()
    {
    DateTime t1=DateTime.Now;
    StringBuilder s=new StringBuilder();
    for (int i=0;i<50000;i++)
    {
    s.Append("a");
    }
    DateTime t2=DateTime.Now;
    Console.WriteLine(t2-t1);
    }
    }
    }
    运行结果:00:00:00.0100144
      

  8.   

    漏了一段代码
    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代码好像很多,其实意思很简单
      

  9.   

    楼上的,你的例子太极端了.
    统计应该是这样做的:
    当然可以指定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();
    }
    }
    }
      

  10.   

    谢谢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(芝麻开门)兄,向你学习!;-)
      

  11.   

    不能吧,我觉得如果字符数是固定的话,StringBuilder怎么也不可能比Concat快,因为Concat一次就将内存分配完毕,而StringBuilder如果初次分配的内存不够的话,还要再次分配内存。可这没有太大的意义了,不是太极端(比如:StringBuilder s=new StringBuilder(1))的话,差别是可以忽略的。
      

  12.   

    在循环中,Contact很难用的。
    所以我一般也是用StringBuilder我睡了。
      

  13.   

    我还没睡。:)>> 使用
    >> 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()要好一点——这个不用装箱。
      

  14.   

    继续讨论:对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,

      

  15.   

    看错了,qqchen79(知秋一叶)说得没错,眼花了。双眼通红,;-(
      

  16.   

    呵呵,不好意思,
    smilefox(笑面狐):
    能否告知一下你是在哪里搞到的Compuware Devpartner?
    谢谢。
      

  17.   

    www.compuware.com
    www.compuware-china.comCompuware Numega DevpartnerNumega的东西应该知道吧,softice,boudschecker。。
      

  18.   

    刚刚用Devpartner测了一下:string s=s1+s2+s3;//执行时间1.2819毫秒string  d=s+1;//这里有一个隐含的装箱
    执行时间61.0279毫秒
    看来装箱操作对性能影响较为明显。机器配置:PIII650 256M DELL Latitude笔记本电脑
      

  19.   

    知秋是对的,我写那段的时候,感觉是Concat将会象WriteLine一样,不用装箱了。看样子不能过过分依赖感觉,今天我看了一下Concat的所有重载方法,统统需要引用类型作为参数,也就是说值类型需要先装箱。