我经常感到困惑的是,是否应该优先考虑这两种给定样式中的任何一种,以打印出需要较小连续的字符串。
string temp = "test";
Console.WriteLine("this is a " + temp);
Console.WriteLine("this is a {0}", temp);
是否存在任何利益/损害,使用一种优于另一种,还是只是偏好?
感谢。
答案 0 :(得分:4)
正如您所说,任何性能问题都是微不足道的,所以请根据您的偏好使用。
我会偶尔在一次性原型或概念验证应用程序中使用第一种方法,但我会将第二种方法专门用于任何可能达到生产的方法。
我的逻辑是第一种格式更容易,更快速地写入,但第二种格式更适合阅读和维护,例如:如果你需要添加一个,他们将如何改变。到句子的结尾?
Console.WriteLine("this is a " + temp + "." );
vs
Console.WriteLine("this is a {0}.", temp);
答案 1 :(得分:4)
编辑:我的原始答案刚刚指出IL的两种技术;我的意图是建议达伦把这些作为起点。 Ani(评论)表示,这还不足以得到明确答案。我决定看一看,所以在这里发布了我向Darren建议的流程大纲,希望能够显示要完成的流程,并揭示其他人如何能够立即说“o,x使用字符串: :格式”
所以:天真地,我希望第一个更有效率 因为所有CLR需要组合两个字符串,而第二个使用广义字符串 获取对象的方法,因此需要将该对象转换为 一个字符串。即使转换是微不足道的,它仍然需要通过一些 在最终发现字符串不需要之前接管电话 转换。我使用ildasm查看了IL,看看发生了什么 - 同样我们可以使用可能更具可读性的Reflector。
对于它的价值 - 我想我会使用StringBuilder.Append 无论如何,开始吧。
在第一个(+)实例中,我们调用了String :: Concat(字符串,字符串)(如果你查看IL,它几乎可以满足你所期望的那样),然后是 一个Console.WriteLine(字符串)。
IL_000d: call string [mscorlib]System.String::Concat(string, string) IL_0012: call void [mscorlib]System.Console::WriteLine(string)
Console.WriteLine(string)实际上只调用TextWriter :: WriteLine(string)。 对于第一种方法来说太多了。
第二种方法调用Console.WriteLine(string,object):
IL_000d: call void [mscorlib]System.Console::WriteLine(string, object)
如果我们反汇编Console :: WriteLine(在mscorlib中),我们看到它调用TextWriter :: WriteLine(string,object):
.method public hidebysig static void WriteLine(string format, object arg0) cil managed ... IL_0007: callvirt instance void System.IO.TextWriter::WriteLine(string, object)
,反汇编,调用String :: Format(...):
.method public hidebysig newslot virtual instance void WriteLine(string format, object arg0) cil managed ... IL_0014: call string System.String::Format(class System.IFormatProvider, string,
在这种情况下,String :: Format实际上创建了一个StringBuilder 使用初始字符串:
.method public hidebysig static string Format(class System.IFormatProvider provider, string format, ... IL_0027: newobj instance void System.Text.StringBuilder::.ctor(int32)
然后必须使用对象
调用StringBuilder :: AppendFormatIL_0031: callvirt instance class System.Text.StringBuilder System.Text.StringBuilder::AppendFormat(class System.IFormatProvider, string, object[])
为了填写它。 StringBuilder :: AppendFormat然后必须转换 对象,以便它可以在最终调用TextWriter :: WriteLine(string)之前将其作为字符串附加。
总结那个批次,最终都调用TextWriter :: WriteLine(string),所以它们的区别在于 第一次打电话
String::Concat(string, string)
和第二次调用
Console::WriteLine(string, object), TextWriter::WriteLine(string, object) String::Format(...). String::StringBuilder().ctor String::StringBuilder().AppendFormat(...)
(和管道)基本上做同样的工作。
在引擎盖下发生了惊人的数量 第二。 StringBuilder的:: ApendFormat 很容易就是最复杂的部分,实际上我的IL还不够好 弄清楚它是否有早期逃脱,例如它发现了 传递的对象是一个字符串...但它必须考虑它的事实意味着它 必须做一些额外的工作。
因此,两者之间存在潜在的差异。第一个看起来更多 如果你知道你有两个字符串要结合,效率很高,这可能是一个好处。它会 有趣的是看一下第一个与从一开始就使用StringBuilder的比较。
评论和更正表示欢迎..并希望它有助于澄清我的答案。
答案 2 :(得分:2)
如果忽略输出到控制台,这实际上是单个连接的连接和格式字符串之间的选择。
这是一个偏好的问题。
在这种情况下,我个人会使用+
版本 - 它更短但同样可读。当需要比此简单连接更复杂的格式时,格式字符串确实闪耀,例如,如果您需要所需输出的 middle 中的任意字符。正如SWeko指出的那样,格式版本有助于简化可维护性,但就我而言,这并不是一个难题(从一个版本到另一个版本并不难;更好的是,像Resharper这样的工具可以做到这一点代表你。
我会指出一个(与90%的情况无关)事实:+
版本可能稍微更高效,因为在运行时没有要解析的格式字符串-时间。 (与任何其他性能问题一样,您需要针对特定情况进行衡量,以证明选择其中一个是合理的。)
答案 3 :(得分:2)
在这种情况下,第一个更易读。由于只有一个参数,因此Perfromance可能也会快一点。
使用+
连接器变得不可读,并且在中间位置有一些参数。
第二个使用内部使用String.Format(...)
的{{1}}。
答案 4 :(得分:2)
但是存在一些差异。
第一行创建一个新字符串,然后将其发送到WriteLine方法。
在第二种形式中,WriteLine在内部调用string.Format(),它在内部使用StringBuilder来构建将要写入的最终字符串。
在某些情况下,使用第二种形式可能会更好(特别是当有多个参数时)。
答案 5 :(得分:1)
从这个角度来看,如果我在散布文本的过程中有很多参数,我会使用后一种方法。在简单的情况下,您显示我会选择前者。
如果使用所有字符串,它们将是等效的。但是,如果您使用了大量参数并且关注性能,我建议使用第一个样式和StringBuilder来创建该行。