5

次のような文字列を追加するStringBuilderオブジェクトがあります。

ここでどちらがより良いアプローチかを知りたいのですが、最初のアプローチは次のとおりです。

StringBuilder sb = new StringBuilder();
sb.Append("Hello" + "How" + "are" + "you");

2つ目は次のとおりです。

StringBuilder sb = new StringBuilder();
sb.Append("Hello").Append("How").Append("are").Append("you");
4

5 に答える 5

10

現在の例では、文字列リテラル:

"Hello" + "How" + "are" + "you"

コンパイラによって 1 つの定数文字列リテラルにコンパイルされるため、技術的には次よりも高速です。

sb.Append("Hello").Append("How").Append("are").Append("you");

ただし、文字列変数を使用した場合:

sb.Append(s1 + s2 + s3 + s4);

次に、前者は最終的な文字列をメソッドに渡す前にAppend一連の文字列を作成する可能性があるため(連結のため)、後者はより高速になりますが、後者は余分な文字列の作成を回避します(ただし、余分なメソッド呼び出しと内部バッファをトレードオフします)サイズ変更)。

更新:さらに明確にするために、連結される項目が 4 つしかないこの正確な状況では、コンパイラは への呼び出しを発行しString.Concat(string, string, string, string)ますStringBuilder

于 2012-08-13T16:03:20.237 に答える
7

最初の方が効率的です。コンパイラはそれを次の単一の呼び出しに変換します。

StringBuilder sb = new StringBuilder();
sb.Append("HelloHowareyou");

パフォーマンスの測定

どちらが速いかを知る最善の方法は、測定することです。要点は次のとおりです。結果は次のとおりです (時間が短いほど速いことを意味します)。

sb.Append("Hello" + "How" + "are" + "you")                  : 11.428s
sb.Append("Hello").Append("How").Append("are").Append("you"): 15.314s
sb.Append(a + b + c + d)                                    : 21.970s
sb.Append(a).Append(b).Append(c).Append(d)                  : 15.529s

与えられた数値は、タイトなループで操作を 1 億回実行するのにかかる秒数です。

結論

  • 最も速いのは、文字列リテラルと+.
  • ただし、変数がある場合は、 を使用するAppend方が より高速です+。への余分な呼び出しのため、最初のバージョンは遅くなりますString.Concat

これを自分でテストしたい場合は、上記のタイミングを取得するために使用したプログラムを次に示します。

using System;
using System.Text;

public class Program
{
    public static void Main()
    {
        DateTime start, end;
        int numberOfIterations = 100000000;
        start = DateTime.UtcNow;
        for (int i = 0; i < numberOfIterations; ++i)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Hello" + "How" + "are" + "you");
        }
        end = DateTime.UtcNow;
        DisplayResult("sb.Append(\"Hello\" + \"How\" + \"are\" + \"you\")", start, end);

        start = DateTime.UtcNow;
        for (int i = 0; i < numberOfIterations; ++i)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Hello").Append("How").Append("are").Append("you");
        }
        end = DateTime.UtcNow;
        DisplayResult("sb.Append(\"Hello\").Append(\"How\").Append(\"are\").Append(\"you\")", start, end);

        string a = "Hello";
        string b = "How";
        string c = "are";
        string d = "you";

        start = DateTime.UtcNow;
        for (int i = 0; i < numberOfIterations; ++i)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(a + b + c + d);
        }
        end = DateTime.UtcNow;
        DisplayResult("sb.Append(a + b + c + d)", start, end);

        start = DateTime.UtcNow;
        for (int i = 0; i < numberOfIterations; ++i)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(a).Append(b).Append(c).Append(d);
        }
        end = DateTime.UtcNow;
        DisplayResult("sb.Append(a).Append(b).Append(c).Append(d)", start, end);

        Console.ReadLine();
    }

    private static void DisplayResult(string name, DateTime start, DateTime end)
    {
        Console.WriteLine("{0,-60}: {1,6:0.000}s", name, (end - start).TotalSeconds);
    }
}
于 2012-08-13T16:03:06.480 に答える
4

文字列定数は、コンパイル時にコンパイラによって連結されます。連結する文字列式が 4 つ以下の場合、コンパイラは次の呼び出しを発行します。String.Concat

s + t + u + v ==> String.Concat(s, t, u, v)

これは、内部バッファーのサイズを変更する必要があるためStringBuilder、 よりも高速に実行されますが、結果として得られる合計の長さを事前に計算できます。ただし、結果の文字列の最大長が事前にわかっている場合は、初期作業バッファー サイズを指定して初期化できます。StringBuilderConcatStringBuilder

var sb = new StringBuilder(initialBufferSize);

StringBuilder多くの場合、ループやその他の動的なシナリオで使用され、s += tそのような場合よりも高速に実行されます。

于 2012-08-13T16:21:25.047 に答える
0

最初のケースでは、コンパイラは 1 つの文字列を作成するため、Append は 1 回だけ呼び出します。しかし、これが大きな違いをもたらすとは思えません。測定値は何を示しましたか?

于 2012-08-13T16:03:27.353 に答える
-5

2つ目は、より良いアプローチです。文字列は不変です。つまり、sb.Append( "Hello" + "How" + "Are" + "You")を使用すると、文字列の複数のコピーが作成されます。

例えば

"Hello"

それから

"HelloHow"

それから

"HelloHowAre"

2番目のコードははるかにパフォーマンスが高い

編集:もちろん、これはコンパイラの最適化を考慮していませんが、意図したとおりにクラスを使用するのが最善です

これらはリテラルであるため、人々が指摘しているように、コンパイラはこれらの操作の最適化を処理します-しかし、私のポイントは、文字列の連結を行うことは、StringBuilderが避けようとしていることです

たとえば、次のように数回ループします。

var someString = "";

foreach (var s in someListOfStrings) 
{
    someString += s;
}

するほど良くはありません:

var sb = new StringBuilder();

foreach(var s in someListOfStrings)
{
    sb.Append(s);
}

sb.ToString();

前に言ったように、文字列は不変なので、これはおそらくはるかに速いでしょう

以来、OPは一般的に連結の使用について話していると思いました

sb.Append("Hello" + "How");

完全に無意味に見えるとき

sb.Append("HelloHow");

もっと論理的だろう...?

OPの考えでは、プレースホルダーテキストは最終的に変数のシェッドロードになるように思われます...

于 2012-08-13T16:03:52.697 に答える