19

メソッドで StringBuilder オブジェクトを使用して文字列を作成している場合、次のことは理にかなっていますか?

StringBuilder オブジェクトを返し、呼び出し元のコードで ToString()? を呼び出すようにします。

return sb;

または自分で ToString() を呼び出して文字列を返します。

return sb.ToString();

小さい文字列を返す場合と大きい文字列を返す場合では、違いがあると思います。それぞれのケースで何が適切でしょうか?前もって感謝します。

編集:呼び出しコードの文字列をさらに変更する予定はありませんが、Colin Burnett は良い点です。

主に、StringBuilder オブジェクトまたは文字列を返す方が効率的ですか? 文字列への参照が返されますか、それともコピーですか?

4

11 に答える 11

24

文字列をさらに変更する場合は StringBuilder を返し、それ以外の場合は文字列を返します。これは API に関する質問です。

効率について。これは詳細のない漠然とした/一般的な質問なので、変更可能か不変かはパフォーマンスよりも重要だと思います。可変性は、API が変更可能なオブジェクトを返すようにする API の問題です。これには文字列の長さは関係ありません。

それは言った。Reflector を使用して StringBuilder.ToString を見ると、次のようになります。

public override string ToString()
{
    string stringValue = this.m_StringValue;
    if (this.m_currentThread != Thread.InternalGetCurrentThread())
    {
        return string.InternalCopy(stringValue);
    }
    if ((2 * stringValue.Length) < stringValue.ArrayLength)
    {
        return string.InternalCopy(stringValue);
    }
    stringValue.ClearPostNullChar();
    this.m_currentThread = IntPtr.Zero;
    return stringValue;
}

コピーが作成されることがわかりますが、StringBuilder で変更するとコピーが作成されます (これが m_currentThread のポイントであると言えます。これは、Append がこれをチェックし、現在のスレッドと一致しない場合はコピーするためです) .

これの終わりは、 StringBuilder を変更しない場合、文字列をコピーせず、長さは効率とは無関係であるということだと思います (その 2 番目の if にヒットしない限り)。

アップデート

System.String は、(値型ではなく) 参照型であることを意味するクラスであるため、「string foo;」基本的にポインタです。(文字列をメソッドに渡すと、コピーではなくポインターが渡されます。) System.String は、mscorlib 内では変更可能ですが、mscorlib の外では不変です。これが、StringBuilder が文字列を操作できる方法です。

そのため、ToString() が呼び出されると、内部の文字列オブジェクトが参照によって返されます。コードが mscorlib にないため、この時点では変更できません。m_currentThread フィールドをゼロに設定すると、StringBuilder でさらに操作を行うと、文字列オブジェクトがコピーされ、ToString() で返された文字列オブジェクトを変更できなくなります。このことを考慮:

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

string foo = sb.ToString();

sb.Append("World");

string bar = sb.ToString();

StringBuilder がコピーを作成しなかった場合、StringBuilder が変更したため、最後に foo は「Hello World」になります。しかし、コピーを作成したので、foo はまだ "Hello" で、bar は "Hello World" です。

それはリターン/リファレンス全体を明確にしていますか?

于 2009-05-07T12:55:00.450 に答える
5

この質問では、パフォーマンスが要因になるべきではないと思います。いずれにせよ、誰かが sb.ToString() を呼び出すので、どこかでヒットします。

より重要な問題は、メソッドと目的の意図は何かです。このメソッドがビルダーの一部である場合、文字列ビルダーを返すことがあります。そうでなければ、文字列を返します。

これがパブリック API の一部である場合、ビルダーではなく文字列を返すことに傾倒します。

于 2009-05-07T12:55:30.353 に答える
3

StringBuilderメソッドの実装の詳細です。パフォーマンスの問題が発生するまで string を返す必要があります。その時点で、間接化を導入し、内部実装の決定から保護するのに役立つ別のパターン (ビジター パターンなど) を調査する必要があります。

文字列は常にヒープに格納されるため、戻り値の型が文字列の場合は参照が返されます。ただし、2 つの同一の文字列が同一の参照を持つとは限りません。一般に、文字列は実際には参照型ですが、値型であるかのように考えるのが安全です。

于 2009-05-07T13:05:08.380 に答える
3

メソッドは sb.ToString() を返す必要があると思います。StringBuilder() オブジェクトの作成を取り巻くロジックが将来変更される必要がある場合、メソッドを呼び出してから別のことを行う各シナリオではなく、メソッドで変更することは理にかなっています

于 2009-05-07T12:55:32.757 に答える
1

sb.ToString() を返します。メソッドは手元にあるものだけに集中する必要があり (この場合は文字列を作成します)、さらに操作するために返されないようにする必要があります。

于 2009-05-07T13:03:41.473 に答える
1

あなたはもうそれを変更するつもりはないので

return sb.ToString();

最も効率的であるべき

于 2009-05-07T13:01:04.600 に答える
1

それは、出力で何をしようとしているかによって異なります。私は個人的に文字列を返します。そうすれば、stringbuilder を使用しないように途中でメソッドを変更する必要がある場合でも、戻り値としてそれで立ち往生することはありません。

ちょっと考えてみると、答えはずっと明確です。どちらを返すべきかという質問は、実際にその質問に答えます。返されるオブジェクトは文字列である必要があります。その理由は、「文字列で十分な場合に StringBuilder オブジェクトを返す理由はありますか?」という質問をしている場合です。答えはノーです。理由があれば、stringbuilder のメソッドとプロパティが必要なため、string を返すことは問題外です。

于 2009-05-07T12:55:55.220 に答える
1

メソッドを離れたら、文字列で何をしているかに依存すると思います。追加を続ける場合は、効率を高めるために stringbuilder を返すことを検討してください。常に .ToString() を呼び出す場合は、カプセル化を改善するためにメソッド内でそれを行う必要があります。

于 2009-05-07T12:56:21.333 に答える
1

string特にメソッドがパブリック API の一部である場合は、ほとんどすべての状況でa を返します。

例外は、メソッドがより大きなプライベートな「ビルダー」プロセスの一部にすぎず、呼び出し元のコードがさらに操作を行う場合です。その場合、私はおそらく を返すことを検討しStringBuilderます。

于 2009-05-07T12:57:36.340 に答える
0

メソッドには具体的なタスクが与えられており、それを完了して、それ以上の処理を必要としない完成した結果を返すことが期待されます。本当に必要な場合にのみ StringBuilder を返します。その場合、何か特別なものを返すことを示すために、メソッド名にも何かを追加してください。

于 2009-05-07T13:16:08.870 に答える
0

文字列にさらにものを追加し、他の stringbuilder 関連の機能を使用する必要がある場合は、stringbuilder を返します。それ以外の場合は、文字列自体を使用している場合は、文字列を返します。

他にも技術的な考慮事項がありますが、それは最高レベルの懸念事項です。

于 2009-05-07T12:55:40.213 に答える