1

次のコードはどのように機能しますか?

public void SomeMethod()
{
    StringBuilder sb = new StringBuilder();
    AppendFoo(sb);
    String foo = sb.ToString(); // foo is "foo"

    String s = String.Empty;
    AppendBar(s);
    String bar = s; // bar is empty 
}

public void AppendFoo(StringBuilder x)
{
    x.Append("Foo");
}

public void AppendBar(String x)
{
    x = x + "Bar";
}

StringBuilderとの両方Stringが参照型である場合、メソッドを介して渡すときに文字列オブジェクトが変更されないのはなぜですか? メソッドへの両方のパラメーターが参照型をパラメーターとして取っているためAppendBar、StringBuilder オブジェクトはメソッドに渡すときに変更されます。AppendFoo

4

6 に答える 6

13

文字列が今のところ不変であるという事実を無視してください-それは少し赤いニシンです。重要な点は、次の違いです。

x.Append(...);

x = x + ...;

それらをよく見てください。最初のものは、を参照するオブジェクトに作用x、の内容を変更しStringBuilderます。2つ目は、の値を変更xして別のオブジェクト(新しい文字列)を参照することです。既存のオブジェクトの内容は変更されません。(実際、文字列は不変であるためできませんでしたが、とにかく同じロジックが適用されます。)

メソッド内のの値を変更してxも、初期化に使用される引数の値は変更されませんx

重要な点は、変数の値を変更することと、変数が参照するオブジェクトの内容を変更することを区別することです。その違いがわかれば、残りは適切な場所に収まるはずです。

パラメータの受け渡しに関する私の記事でこれとパラメータの詳細を読み、別の記事で参照型と値型の詳細を読んでください。

于 2009-11-21T18:27:16.060 に答える
2

文字列は不変です。一度作成すると変更できません。

appendBar で何が起こるかは次のとおりです。

x= x+"バー"

(新しい値で) 新しい文字列を作成し、参照 x をそれに設定します。(実際の実装はコンパイラに依存します)

ただし、呼び出しコード内の参照 s は、元の文字列オブジェクトを指しています。

于 2009-11-21T18:20:34.170 に答える
1

最初の呼び出しでAppendFoo、引数のメソッド メンバーを呼び出して引数を変更します。

2 番目の呼び出しでAppendBar、引数に新しい値を割り当てます。元の引数は反映されません (ref で呼び出さない限り)

たとえば、最初の呼び出しが次のようになっているとします。

public void AppendFoo(StringBuilder x)
{
    x = new StringBuilder();
    x.Append("Foo");
}

同じ結果が得られたでしょう。

文字列が不変であるという事実に関連していると考えたくなりますが、それとは何の関係もありません。引数に新しい値を代入するだけなので、メソッドに送信される元のオブジェクトは変更されません。

于 2009-11-21T18:21:01.517 に答える
1

文字列は参照型ですが、C# では不変です。つまり、一度割り当てられると、内容が変更されることはありません。あなたが言うときあなたがしていることすべて

x = x + "Bar";

is 'x+"Bar" を含む新しい文字列を作成し、それを x のローカル参照に割り当てます。文字列を 'ref' パラメーターとして渡さなかったため、ローカル参照に割り当てても、関数の外部の参照には影響しません。

于 2009-11-21T18:21:28.287 に答える
0

文字列が不変であることはまったく問題ではありません。AppendBar関数にrefパラメータがありません。

public void AppendBar(ref String x)
{
    x = x + "Bar";
}

AppendFooがだった場合、ロジックは同じです

public void AppendFoo(StringBuilder x)
{
    x = new StringBuilder();
    x.Append("Foo");
}

どちらも機能しません...参照の値を変更する場合は、xvarをrefとして宣言する必要があります。

于 2009-11-21T18:35:09.757 に答える
0

.NET 文字列は、実際には不変のデータ型です。つまり、文字列オブジェクトを初期化すると、その文字列オブジェクトは変更できなくなります。文字列の内容を変更するように見える演算子は、実際には新しい文字列を作成し、変数に格納されているアドレスを新しく作成された文字列のアドレスに更新します。古い文字列は参照されなくなります。

AppendBar(string x)たとえば、文字列を関数に渡す場合x = x + "Bar"、.NET ランタイムは、結合されたテキストを格納するのに十分なメモリを割り当てます。サンプルで空の元のテキストと "Bar" が新しい文字列インスタンスにコピーされます。 x新しい文字列インスタンスのアドレスを指すように更新されます。ただし、はにコピーとしてs渡されるため、呼び出し元メソッドの の値は、新しい文字列インスタンスを指すように更新されません。古いもの、空の文字列のアドレスをまだ保存しています。したがって、関数を呼び出した後、 を参照しても空の文字列が生成されます。AppendBar(string x)ss

関数のシグネチャを変更して、関数にAppendBar(ref string x)渡される文字列を変更できます。ステートメントの後AppendBar(ref s);s「is」、「Bar」の順に続きます。

于 2009-11-21T18:54:16.223 に答える