StringまたはStringBuilderは値を返しますか?
-
08-07-2019 - |
質問
メソッドでStringBuilderオブジェクトを使用して文字列を作成している場合、次のことが意味をなします:
StringBuilderオブジェクトを返し、呼び出し元のコードがToString()を呼び出すようにしますか?
return sb;
OR ToString()を自分で呼び出して文字列を返します。
return sb.ToString();
小さな文字列または大きな文字列を返す場合、違いが生じると思います。それぞれの場合に適切なものは何ですか?事前に感謝します。
編集: 呼び出し元のコードの文字列をさらに変更する予定はありませんが、良い点はコリンバーネットです。
主に、StringBuilderオブジェクトまたは文字列を返す方が効率的ですか?文字列への参照が返されますか、それともコピーですか?
解決
さらに文字列を変更する場合は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でそれを変更すると、それからコピーを作成することがわかります(これはmendがこれをチェックし、それが現在のスレッド)。
これで終わりは、StringBuilderを変更しない場合、文字列をコピーせず、長さが効率に関係ないことです(2番目のifをヒットしない限り)。
更新
System.Stringはクラスであるため、(値型ではなく)参照型であるため、&quot; string foo;&quot;本質的にポインタです。 (文字列をメソッドに渡すと、コピーではなくポインタが渡されます。)System.Stringは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がコピーを作成しなかった場合、最後のfooは&quot; Hello World&quot;になります。 StringBuilderが変更したためです。しかし、コピーを作成したので、fooはまだ&quot; Hello&quot;のままです。バーは&quot; Hello World&quot;です。
これにより、返品/参照全体が明確になりますか?
他のヒント
パフォーマンスがこの問題の要因になるとは思わない。いずれにせよ、誰かがsb.ToString()を呼び出して、どこかでヒットするようにします。
より重要な質問は、メソッドの目的と目的は何かということです。このメソッドがビルダーの一部である場合、文字列ビルダーを返すことがあります。そうでなければ、文字列を返します。
これがパブリックAPIの一部である場合、ビルダーではなく文字列を返すようになります。
メソッドはsb.ToString()を返すべきだと思います。 StringBuilder()オブジェクトの作成を取り巻くロジックが将来変更される場合、メソッドを呼び出してから他のことを行う各シナリオではなく、メソッドで変更されることは理にかなっています
StringBuilder
は、メソッドの実装の詳細です。パフォーマンスの問題になるまで文字列を返す必要があります。その時点で、別のパターン(訪問者パターン)間接性を導入し、内部実装の決定から保護するのに役立ちます。
文字列は常にヒープに格納されるため、戻り値の型が文字列の場合、参照が返されます。ただし、2つの同一の文字列が同一の参照を持つとは考えられません。一般に、実際には参照型であるにもかかわらず、文字列を値型であると考えるのが安全です。
文字列がメソッドを出ると、文字列で何をしているのかによります。追加を続ける場合は、効率を高めるために文字列ビルダーを返すことを検討してください。常に.ToString()を呼び出す場合は、カプセル化を改善するためにメソッド内で行う必要があります。
ほとんどすべての状況で、特にメソッドがパブリックAPIの一部である場合、 string
を返します。
例外は、メソッドがより大きなプライベートな「ビルダー」の一部にすぎない場合です。プロセスと呼び出しコードはさらに操作を行います。その場合、 StringBuilder
を返すことを検討します。
もう変更しないので
return sb.ToString();
最も効率的でなければなりません
sb.ToString()を返します。メソッドは、手元にあるもの(この場合は文字列を作成します)に集中し、IMOをさらに操作するために返されないようにする必要があります。
これは、出力をどのように処理するかによって異なります。私は個人的に文字列を返します。そうすれば、メソッドを文字列ビルダーを使用しないように変更する必要がある場合は、戻り値としてそれで立ち往生することはありません。
今のところ考えてみると、答えはずっと明確です。返すべき質問は本当に質問に答えます。返されるオブジェクトは文字列でなければなりません。理由は、質問をしている場合、「文字列が実行されるときにStringBuilderオブジェクトを返す理由はありますか?」答えはノーです。理由がある場合、stringbuilderのメソッドとプロパティが必要なので、文字列を返すことは問題外です。
より多くのものを文字列に追加し、他の文字列ビルダー関連機能を使用する必要がある場合は、文字列ビルダーを返します。それ以外の場合、文字列自体を使用している場合は、文字列を返します。
他にも技術的な考慮事項がありますが、それは最高レベルの懸念です。
メソッドには具体的なタスクが与えられ、メソッドを完了し、さらに処理する必要のない最終結果を返すことが期待されます。本当に必要なときだけStringBuilderを返します。その場合、メソッド名に何かを追加して、何か特別なものを返すことを示します。