C# String.Format 和 StringBuilder 一样有效吗

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6785/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-07-31 16:44:37  来源:igfitidea点击:

Is String.Format as efficient as StringBuilder

提问by lomaxx

Suppose I have a stringbuilder in C# that does this:

假设我在 C# 中有一个 stringbuilder 可以执行此操作:

StringBuilder sb = new StringBuilder();
string cat = "cat";
sb.Append("the ").Append(cat).(" in the hat");
string s = sb.ToString();

would that be as efficient or any more efficient as having:

这是否与以下内容一样有效或更有效:

string cat = "cat";
string s = String.Format("The {0} in the hat", cat);

If so, why?

如果是这样,为什么?

EDIT

编辑

After some interesting answers, I realised I probably should have been a little clearer in what I was asking. I wasn't so much asking for which was quicker at concatenating a string, but which is quicker at injectingone string into another.

在得到一些有趣的答案之后,我意识到我可能应该对我的问题更清楚一些。我并不是在问哪个在连接字符串时更快,但在一个字符串注入另一个字符串时哪个更快。

In both cases above I want to inject one or more strings into the middle of a predefined template string.

在上述两种情况下,我都想将一个或多个字符串注入预定义模板字符串的中间。

Sorry for the confusion

对困惑感到抱歉

采纳答案by Kev

NOTE:This answer was written when .NET 2.0 was the current version. This may no longer apply to later versions.

注意:此答案是在 .NET 2.0 是当前版本时编写的。这可能不再适用于更高版本。

String.Formatuses a StringBuilderinternally:

String.FormatStringBuilder内部使用:

public static string Format(IFormatProvider provider, string format, params object[] args)
{
    if ((format == null) || (args == null))
    {
        throw new ArgumentNullException((format == null) ? "format" : "args");
    }

    StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
    builder.AppendFormat(provider, format, args);
    return builder.ToString();
}

The above code is a snippet from mscorlib, so the question becomes "is StringBuilder.Append()faster than StringBuilder.AppendFormat()"?

上面的代码是 mscorlib 的一个片段,所以问题变成了“StringBuilder.Append()StringBuilder.AppendFormat()”快吗?

Without benchmarking I'd probably say that the code sample above would run more quickly using .Append(). But it's a guess, try benchmarking and/or profiling the two to get a proper comparison.

如果没有基准测试,我可能会说上面的代码示例使用.Append(). 但这是一个猜测,尝试对两者进行基准测试和/或分析以进行适当的比较。

This chap, Jerry Dixon, did some benchmarking:

这位 Jerry Dixon 做了一些基准测试:

http://jdixon.dotnetdevelopersjournal.com/string_concatenation_stringbuilder_and_stringformat.htm

http://jdixon.dotnetdevelopersjournal.com/string_concatenation_stringbuilder_and_stringformat.htm

Updated:

更新:

Sadly the link above has since died. However there's still a copy on the Way Back Machine:

可悲的是,上面的链接已经死了。然而,Way Back Machine 上仍然有一个副本:

http://web.archive.org/web/20090417100252/http://jdixon.dotnetdevelopersjournal.com/string_concatenation_stringbuilder_and_stringformat.htm

http://web.archive.org/web/20090417100252/http://jdixon.dotnetdevelopersjournal.com/string_concatenation_stringbuilder_and_stringformat.htm

At the end of the day it depends whether your string formatting is going to be called repetitively, i.e. you're doing some serious text processing over 100's of megabytes of text, or whether it's being called when a user clicks a button now and again. Unless you're doing some huge batch processing job I'd stick with String.Format, it aids code readability. If you suspect a perf bottleneck then stick a profiler on your code and see where it really is.

归根结底,这取决于您的字符串格式是否会被重复调用,即您正在对 100 兆字节的文本进行一些严肃的文本处理,或者是否在用户一次又一次单击按钮时被调用。除非你正在做一些巨大的批处理工作,否则我会坚持使用 String.Format,它有助于代码可读性。如果您怀疑性能瓶颈,那么在您的代码上贴一个分析器,看看它到底在哪里。

回答by GateKiller

I would suggest not, since String.Format was not designed for concatenation, it was design for formatting the output of various inputs such as a date.

我建议不要,因为 String.Format 不是为连接而设计的,它是为格式化各种输入(如日期)的输出而设计的。

String s = String.Format("Today is {0:dd-MMM-yyyy}.", DateTime.Today);

回答by Joseph Daigle

It really depends. For small strings with few concatenations, it's actually faster just to append the strings.

这真的取决于。对于连接很少的小字符串,实际上只是附加字符串会更快。

String s = "String A" + "String B";

But for larger string (very very large strings), it's then more efficient to use StringBuilder.

但是对于较大的字符串(非常非常大的字符串),使用 StringBuilder 会更有效。

回答by Greg

From the MSDN documentation:

MSDN 文档

The performance of a concatenation operation for a String or StringBuilder object depends on how often a memory allocation occurs. A String concatenation operation always allocates memory, whereas a StringBuilder concatenation operation only allocates memory if the StringBuilder object buffer is too small to accommodate the new data. Consequently, the String class is preferable for a concatenation operation if a fixed number of String objects are concatenated. In that case, the individual concatenation operations might even be combined into a single operation by the compiler. A StringBuilder object is preferable for a concatenation operation if an arbitrary number of strings are concatenated; for example, if a loop concatenates a random number of strings of user input.

String 或 StringBuilder 对象的串联操作的性能取决于内存分配发生的频率。String 串联操作总是分配内存,而 StringBuilder 串联操作仅在 StringBuilder 对象缓冲区太小而无法容纳新数据时才分配内存。因此,如果连接固定数量的 String 对象,则 String 类更适合用于连接操作。在这种情况下,编译器甚至可能将单个连接操作合并为单个操作。如果连接任意数量的字符串,则 StringBuilder 对象更适合用于连接操作;例如,如果循环连接随机数量的用户输入字符串。

回答by saalon

I think in most cases like this clarity, and not efficiency, should be your biggest concern. Unless you're crushing together tons of strings, or building something for a lower powered mobile device, this probably won't make much of a dent in your run speed.

我认为在大多数情况下,这种清晰度而不是效率应该是您最关心的问题。除非您将成吨的琴弦压在一起,或者为功率较低的移动设备构建一些东西,否则这可能不会对您的运行速度产生太大影响。

I've found that, in cases where I'm building strings in a fairly linear fashion, either doing straight concatenations or using StringBuilder is your best option. I suggest this in cases where the majority of the string that you're building is dynamic. Since very little of the text is static, the most important thing is that it's clear where each piece of dynamic text is being put in case it needs updated in the future.

我发现,在我以相当线性的方式构建字符串的情况下,直接连接或使用 StringBuilder 是您的最佳选择。在您构建的大部分字符串是动态的情况下,我建议这样做。由于很少有文本是静态的,最重要的是清楚每段动态文本的放置位置,以防将来需要更新。

On the other hand, if you're talking about a big chunk of static text with two or three variables in it, even if it's a little less efficient, I think the clarity you gain from string.Format makes it worth it. I used this earlier this week when having to place one bit of dynamic text in the center of a 4 page document. It'll be easier to update that big chunk of text if its in one piece than having to update three pieces that you concatenate together.

另一方面,如果您谈论的是包含两个或三个变量的一大块静态文本,即使效率稍低,我认为您从 string.Format 中获得的清晰度使其值得。本周早些时候,当不得不在 4 页文档的中心放置一点动态文本时,我使用了它。如果将一大块文本整合到一起,则更新大块文本比必须更新连接在一起的三部分更容易。

回答by GateKiller

In both cases above I want to inject one or more strings into the middle of a predefined template string.

在上述两种情况下,我都想将一个或多个字符串注入预定义模板字符串的中间。

In which case, I would suggest String.Format is the quickest because it is design for that exact purpose.

在这种情况下,我建议 String.Format 是最快的,因为它是为此目的而设计的。

回答by McDowell

I would expect String.Formatto be slower - it has to parse the string and thenconcatenate it.

我希望String.Format更慢 - 它必须解析字符串然后连接它。

Couple of notes:

几个注意事项:

  • Formatis the way to go for user-visible strings in professional applications; this avoids localization bugs
  • If you know the length of the resultant string beforehand, use the StringBuilder(Int32)constructor to predefine the capacity
  • 格式是专业应用程序中用户可见字符串的方法;这避免了本地化错误
  • 如果您事先知道结果字符串的长度,请使用StringBuilder(Int32)构造函数来预定义容量

回答by Vaibhav

I ran some quick performance benchmarks, and for 100,000 operations averaged over 10 runs, the first method (String Builder) takes almost half the time of the second (String Format).

我运行了一些快速性能基准测试,对于平均超过 10 次运行的 100,000 次操作,第一种方法(String Builder)几乎是第二种方法(String Format)的一半。

So, if this is infrequent, it doesn't matter. But if it is a common operation, then you may want to use the first method.

所以,如果这种情况很少发生,也没关系。但如果是普通操作,那么你可能要使用第一种方法。

回答by Vaibhav

Oh also, the fastest would be:

哦还有,最快的是:

string cat = "cat";
string s = "The " + cat + " in the hat";

回答by jrista

String.Format uses StringBuilderinternally...so logically that leads to the idea that it would be a little less performant due to more overhead. However, a simple string concatenation is the fastest method of injecting one string between two others...by a significant degree. This evidence was demonstrated by Rico Mariani in his very first Performance Quiz, years ago. Simple fact is that concatenations...when the number of string parts is known (without limitation..you could concatenate a thousand parts...as long as you know its always 1000 parts)...are always faster than StringBuilderor String.Format. They can be performed with a single memory allocation an a series of memory copies. Hereis the proof

String.Format 在StringBuilder内部使用......如此合乎逻辑地导致这样的想法,即由于更多的开销,它的性能会稍差一些。然而,简单的字符串连接是在两个其他字符串之间注入一个字符串的最快方法......在很大程度上。多年前,里科·马里亚尼 (Rico Mariani) 在他的第一次表演测验中证明了这一证据。简单的事实是连接...当字符串部分的数量已知时(没有限制...你可以连接一千个部分...只要你知道它总是1000个部分)...总是比StringBuilder或字符串快。格式。它们可以通过单个内存分配和一系列内存副本来执行。是证据

And here is the actual code for some String.Concat methods, which ultimately call FillStringChecked which uses pointers to copy memory (extracted via Reflector):

下面是一些 String.Concat 方法的实际代码,它们最终调用 FillStringChecked,它使用指针来复制内存(通过 Reflector 提取):

public static string Concat(params string[] values)
{
    int totalLength = 0;

    if (values == null)
    {
        throw new ArgumentNullException("values");
    }

    string[] strArray = new string[values.Length];

    for (int i = 0; i < values.Length; i++)
    {
        string str = values[i];
        strArray[i] = (str == null) ? Empty : str;
        totalLength += strArray[i].Length;

        if (totalLength < 0)
        {
            throw new OutOfMemoryException();
        }
    }

    return ConcatArray(strArray, totalLength);
}

public static string Concat(string str0, string str1, string str2, string str3)
{
    if (((str0 == null) && (str1 == null)) && ((str2 == null) && (str3 == null)))
    {
        return Empty;
    }

    if (str0 == null)
    {
        str0 = Empty;
    }

    if (str1 == null)
    {
        str1 = Empty;
    }

    if (str2 == null)
    {
        str2 = Empty;
    }

    if (str3 == null)
    {
        str3 = Empty;
    }

    int length = ((str0.Length + str1.Length) + str2.Length) + str3.Length;
    string dest = FastAllocateString(length);
    FillStringChecked(dest, 0, str0);
    FillStringChecked(dest, str0.Length, str1);
    FillStringChecked(dest, str0.Length + str1.Length, str2);
    FillStringChecked(dest, (str0.Length + str1.Length) + str2.Length, str3);
    return dest;
}

private static string ConcatArray(string[] values, int totalLength)
{
    string dest = FastAllocateString(totalLength);
    int destPos = 0;

    for (int i = 0; i < values.Length; i++)
    {
        FillStringChecked(dest, destPos, values[i]);
        destPos += values[i].Length;
    }

    return dest;
}

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

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

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

So then:

那么:

string what = "cat";
string inthehat = "The " + what + " in the hat!";

Enjoy!

享受!