16

次の方法を考えます。

static void ChangeArray(params string[] array) {

    for (int i = 0; i < array.Length; i++) 
        array[i] = array[i] + "s";
}

これは、文字列の配列を渡して呼び出すと機能します。

string[] array = {"Michael", "Jordan"} // will become {"Michaels", "Jordans"}
ChangeArray(array);

ただし、文字列引数を使用して呼び出すと機能しません。

string Michael = "Michael";
string Jordan = "Jordan";
ChangeArray(Michael, Jordan); // This will NOT change the values of the variables

コンパイラが Michael と Jordan を配列にラップすることは理解していますが、どちらの場合も結果は同じではないでしょうか?

4

3 に答える 3

23

2番目の例は基本的に次のとおりです。

string Michael = "Michael";
string Jordan = "Jordan";
{
    var tmp = new string[] {Michael, Jordan};
    ChangeArray(tmp);
}

それで; 実際には、内部の値tmp 変更されました...しかしtmp、後で破棄されたため、何も表示されません。エミュレートparamsしませref-位置ごとに元の変数に更新しません。または、コードでは、次のようにはなりません。

string Michael = "Michael";
string Jordan = "Jordan";
{
    var tmp = new string[] {Michael, Jordan};
    ChangeArray(tmp);
    Michael = tmp[0];
    Jordan = tmp[1];
}

そのように動作する必要がある場合は、そのようにコーディングするか、代わりにrefパラメーターを受け取るオーバーロードを使用します。

于 2012-09-21T07:33:52.783 に答える
5

その理由はstring、不変の型であるためですstring。配列にラップされるインスタンスを渡します。これで、配列に2つの新しい文字列が含まれます(元の文字列と同じ値ですが、インスタンスが異なります)。配列を変更すると、これらのコピーは破棄され、配列スロットは新しい文字列を保持します。関数が戻ると、一時配列は破棄されます。したがって、元の入力文字列が変更されることはありません(とにかく変更することはできません。これも、string不変であるためです)。

編集コメントでのリーの議論に続いて、この回答を編集しました(以下の議論を完全なものにするために、回答はそのままにしておきます)。不変の部分は確かに問題とは無関係です。主な根本的な問題は、破棄された一時配列に変更が加えられることです。

于 2012-09-21T07:34:41.400 に答える
2

これは奇妙です(私はこれを知りませんでした)が、指定されたとおりです。

パラメータ配列を使用すると、メソッド呼び出しで2つの方法のいずれかで引数を指定できます。

パラメータ配列に指定された引数は、パラメータ配列型に暗黙的に変換可能な型(セクション6.1)の単一の式にすることができます。この場合、パラメーター配列は値パラメーターとまったく同じように機能します。

または、呼び出しでパラメーター配列に0個以上の引数を指定できます。各引数は、パラメーター配列の要素タイプに暗黙的に変換可能なタイプ(セクション6.1)の式です。この場合、呼び出しは、引数の数に対応する長さのパラメーター配列タイプのインスタンスを作成し、指定された引数値で配列インスタンスの要素を初期化し、新しく作成された配列インスタンスを実際の引数として使用します。

于 2012-09-21T07:35:06.293 に答える