拼接字符串【string.Concat】真的比【连接符】更好?

颤菊大师 2010-01-06 02:43:19
依稀记得大概在某个谈论如何优化 ASP.NET 的帖子里,有人说 String.Concat 效率比连接符更佳。
事实上是这样吗?我用IL简单的查看下,似乎不是啊?甚至 连接符还会自动优化。

测试1 C#:

public static void Test1()
{
string s = "123";
s += "456" + 1.ToString() + "789";
}


测试1 IL:
.method public hidebysig static void  Test1() cil managed
{
// 代码大小 34 (0x22)
.maxstack 4
.locals init ([0] string s,
[1] int32 CS$0$0000)
IL_0000: nop
IL_0001: ldstr "123"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldstr "456"
IL_000d: ldc.i4.1
IL_000e: stloc.1
IL_000f: ldloca.s CS$0$0000
IL_0011: call instance string [mscorlib]System.Int32::ToString()
IL_0016: ldstr "789"
IL_001b: call string [mscorlib]System.String::Concat(string,
string,
string,
string)
IL_0020: stloc.0
IL_0021: ret
} // end of method Class1::Test1


--------------------------------------------------------

测试2 C#:

public static void Test2()
{
string s = "123";
s = string.Concat(s, "456", 1.ToString(), "789");
}


测试2 IL:
.method public hidebysig static void  Test2() cil managed
{
// 代码大小 34 (0x22)
.maxstack 4
.locals init ([0] string s,
[1] int32 CS$0$0000)
IL_0000: nop
IL_0001: ldstr "123"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldstr "456"
IL_000d: ldc.i4.1
IL_000e: stloc.1
IL_000f: ldloca.s CS$0$0000
IL_0011: call instance string [mscorlib]System.Int32::ToString()
IL_0016: ldstr "789"
IL_001b: call string [mscorlib]System.String::Concat(string,
string,
string,
string)
IL_0020: stloc.0
IL_0021: ret
} // end of method Class1::Test2


似乎不存在【string.Concat】比【连接符】更有效率之说吧?
...全文
1340 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
lsd123 2010-01-06
  • 打赏
  • 举报
回复
.
bl_song 2010-01-06
  • 打赏
  • 举报
回复
string.concat优于StringBuilder,StringBuiler优于String
http://www.cnblogs.com/JeffreyZhao/archive/2009/11/26/string-concat-perf-1-benchmark.html
m_struggle 2010-01-06
  • 打赏
  • 举报
回复
习惯用连接符进行拼装
颤菊大师 2010-01-06
  • 打赏
  • 举报
回复
MessageBox.Show('1'+'2'+"");

// '1' + '2'
char + char

// char -> int
char + string

这是一个必然的结果。
wartim 2010-01-06
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 mrlen 的回复:]
引用 26 楼 wartim 的回复:
+的确有时过于智能了
MessageBox.Show('1'+'2'+"");
结果是99
'1’被解释成ascii码 97
'2'被解释成整数2

错!
'1' 49
'2' 50

+ 根据优先级

否则你可以试试
MessageBox.Show('1'+('2'+""));

[/Quote]

一时走眼了,开始用'a'在试,潜意识里一直97
vrhero 2010-01-06
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 wartim 的回复:]
+的确有时过于智能了
MessageBox.Show('1'+'2'+"");
结果是99
'1’被解释成ascii码 97
'2'被解释成整数2
[/Quote]
这恰好证明了+的“不智能”...+是很守规矩的,它是完全按照预定义的“运算规则”执行的,即确定类型对+运算符的重载方法...试试下面的代码...
string s = '1' + '2' + "";
s = "" + '1' + '2';
guyehanxinlei 2010-01-06
  • 打赏
  • 举报
回复
学习一下
颤菊大师 2010-01-06
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 wartim 的回复:]
+的确有时过于智能了
MessageBox.Show('1'+'2'+"");
结果是99
'1’被解释成ascii码 97
'2'被解释成整数2
[/Quote]
错!
'1' 49
'2' 50

+ 根据优先级

否则你可以试试
MessageBox.Show('1'+('2'+""));
wartim 2010-01-06
  • 打赏
  • 举报
回复
+的确有时过于智能了
MessageBox.Show('1'+'2'+"");
结果是99
'1’被解释成ascii码 97
'2'被解释成整数2
颤菊大师 2010-01-06
  • 打赏
  • 举报
回复
颤菊大师 2010-01-06
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 wartim 的回复:]
由__arglist顺带发现了一个好东西

http://www.cnblogs.com/Dah/archive/2007/08/19/830164.html

Undocumented C# Keywords: __makeref, __refvalue, __arglist ...
看IL指令到mkrefany, 文档中说它的作用是: "push a typed reference on the stack", 不知道在C#的何种语法会用上这条指令, 于是Google之, 发现了从来没有看过的C#关键字:


Object obj = new Object();



TypedReference typedref = __makeref(obj);



Type type = __reftype(typedref);



Object sameObj = __refvalue( typedref,Object);

。。。
[/Quote]

还真的是关键字!!
颤菊大师 2010-01-06
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 vrhero 的回复:]
引用 19 楼 viena 的回复:
我觉得其实不是效率方面的问题
+最大的问题在于,有可能出现我说的这种错误~

这种问题是避免不了的,这不是+或string.Concat的过错,是人犯的错...

一个较好的习惯是,较多字符串连接用StringBuilder,较少字符串或“对象”的字符串输出连接根据需要用+或string.Concat或string.Format...即使是这样也避免不了如“自定义类型未重写ToString方法输出类型名称”之类的逻辑错误...
[/Quote]
这些是细节上的把握。
纵然经验丰富,也难免神晃时。
您说的这句话:这不是+或string.Concat的过错,是人犯的错
很有道理
wartim 2010-01-06
  • 打赏
  • 举报
回复
由__arglist顺带发现了一个好东西

http://www.cnblogs.com/Dah/archive/2007/08/19/830164.html

Undocumented C# Keywords: __makeref, __refvalue, __arglist ...
看IL指令到mkrefany, 文档中说它的作用是: "push a typed reference on the stack", 不知道在C#的何种语法会用上这条指令, 于是Google之, 发现了从来没有看过的C#关键字:



Object obj = new Object();



TypedReference typedref = __makeref(obj);



Type type = __reftype(typedref);



Object sameObj = __refvalue( typedref,Object);

。。。
颤菊大师 2010-01-06
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 viena 的回复:]
引用 15 楼 vrhero 的回复:
这种所谓“效率”差别没有意义...string.Concat适用的地方一定适用+,+不适用的地方string.Concat也不适用...因为+连接字符串只是string.Concat的另一种代码书写形式,编译时的转换不会影响运行时...


我觉得其实不是效率方面的问题
+最大的问题在于,有可能出现我说的这种错误~
[/Quote]
太好了。你说出了问题所在。
的确如你所说,感谢你的友情提醒。
如你所说,小细节!所以我标题并未写“更快”而是“更好”。
vrhero 2010-01-06
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 viena 的回复:]
我觉得其实不是效率方面的问题
+最大的问题在于,有可能出现我说的这种错误~
[/Quote]
这种问题是避免不了的,这不是+或string.Concat的过错,是人犯的错...

一个较好的习惯是,较多字符串连接用StringBuilder,较少字符串或“对象”的字符串输出连接根据需要用+或string.Concat或string.Format...即使是这样也避免不了如“自定义类型未重写ToString方法输出类型名称”之类的逻辑错误...
viena 2010-01-06
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 vrhero 的回复:]
这种所谓“效率”差别没有意义...string.Concat适用的地方一定适用+,+不适用的地方string.Concat也不适用...因为+连接字符串只是string.Concat的另一种代码书写形式,编译时的转换不会影响运行时...
[/Quote]

我觉得其实不是效率方面的问题
+最大的问题在于,有可能出现我说的这种错误~
viena 2010-01-06
  • 打赏
  • 举报
回复
真不好意思,举例两次都是错的
我的意思是
Console.WriteLine('a'+ 'b' + "c");
Console.WriteLine("a" + "b" + 'c');
结果是不一样的


手动.ToString() 是一个良好习惯
但是有人会有char与string+就不用.ToString()的错觉
毕竟char与string是单个与群体的关系
但是实际上char会被当作数字来相加
两个char+就不是连接了
wartim 2010-01-06
  • 打赏
  • 举报
回复
看了下String.Concat的源码,最后是靠指针赋值,而重载+号的代码找不到

[CLSCompliant(false)]
public static String Concat(Object arg0, Object arg1, Object arg2, Object arg3, __arglist)
{
Object[] objArgs;
int argCount;

ArgIterator args = new ArgIterator(__arglist);
。。。
return Concat(objArgs);
}

public static String Concat(params Object[] args) {
if (args==null) {
throw new ArgumentNullException("args");
}
。。。
return ConcatArray(sArgs, totalLength);
}

private static String ConcatArray(String[] values, int totalLength) {
String result = FastAllocateString(totalLength);
int currPos=0;
。。。
FillStringChecked(result, currPos, values[i]);
currPos+=values[i].Length;
}

return result;
}

unsafe private static void FillStringChecked(String dest, int destPos, String src)
{
int length = src.Length;

if (length > dest.Length - destPos) {
throw new IndexOutOfRangeException();
}

fixed(char *pDest = &dest.m_firstChar)
fixed (char *pSrc = &src.m_firstChar) {
wstrcpy(pDest + destPos, pSrc, length);
}
}

private static unsafe void wstrcpy(char *dmem, char *smem, int charCount)
{
if (charCount > 0) {
#if ALIGN_ACCESS
if ((((int)dmem | (int)smem) & 1) == 0) {
#endif
// First Align dmem to a pointer boundary
if (((int)dmem & 2) != 0)
{
dmem[0] = smem[0];
dmem += 1;
smem += 1;
charCount -= 1;
}
#if WIN64
。。。
}
元宇宙之家 2010-01-06
  • 打赏
  • 举报
回复
多string拼接用StringBuilder吧。
vrhero 2010-01-06
  • 打赏
  • 举报
回复
这种所谓“效率”差别没有意义...string.Concat适用的地方一定适用+,+不适用的地方string.Concat也不适用...因为+连接字符串只是string.Concat的另一种代码书写形式,编译时的转换不会影响运行时...
加载更多回复(14)

110,571

社区成员

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

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

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