次のプログラムをご覧ください。
class Test
{
List<int> myList = new List<int>();
public void TestMethod()
{
myList.Add(100);
myList.Add(50);
myList.Add(10);
ChangeList(myList);
foreach (int i in myList)
{
Console.WriteLine(i);
}
}
private void ChangeList(List<int> myList)
{
myList.Sort();
List<int> myList2 = new List<int>();
myList2.Add(3);
myList2.Add(4);
myList = myList2;
}
}
myList
がref
を通過し、出力が
3
4
リストは確かに「refed by ref」ですが、sort
関数のみが有効になります。次のステートメントmyList = myList2;
は効果がありません。
したがって、出力は実際には次のようになります。
10
50
100
この動作の説明を手伝ってもらえますか?本当にmyList
がpassed-by-refでない場合(myList = myList2
が表示されないように)、myList.Sort()
はどのように有効になりますか?
私はその声明でさえ効果がなく、出力は次のようになると仮定していました。
100
50
10
リストにreferenceを渡しています、しかしare n'tリスト変数を渡していますby reference-したがって、ChangeList
を呼び出すと、変数の値(つまり、参照-「ポインタ」と考える)がコピーされ、パラメータの値ChangeList
内are n'tはTestMethod
から見える。
試してください:
private void ChangeList(ref List<int> myList) {...}
...
ChangeList(ref myList);
次に、これはaをlocal-variablemyRef
への参照に渡します(TestMethod
で宣言)。現在、ChangeList
内でパラメーターを再割り当てすると、変数insideTestMethod
も再割り当てされます。
最初は、次のようにグラフィカルに表現できます。
次に、並べ替えが適用されますmyList.Sort();
最後に、myList' = myList2
を実行すると、参照の1つは失われますが、元の参照は失われず、コレクションはソートされたままになります。
参照(ref
)を使用する場合、myList'
とmyList
は同じになります(1つの参照のみ)。
注:myList'
を使用して、ChangeList
で使用するパラメーターを表します(元の名前と同じ名前を付けたため)
ここにそれを理解する簡単な方法があります
リストはヒープ上に作成されたオブジェクトです。変数myList
は、そのオブジェクトへの参照です。
C#ではオブジェクトを渡すことはありません。値で参照を渡します。
ChangeList
で渡された参照を介してリストオブジェクトにアクセスすると(たとえば、並べ替え中)、元のリストが変更されます。
ChangeList
メソッドへの割り当ては参照の値に対して行われるため、元のリストは変更されません(ヒープ上ではまだメソッド変数で参照されていません)。
this リンクは、C#の参照渡しを理解するのに役立ちます。基本的に、参照型のオブジェクトが値によってメソッドに渡されると、そのオブジェクトで使用可能なメソッドのみがオブジェクトのコンテンツを変更できます。
たとえば、List.sort()メソッドはリストの内容を変更しますが、他のオブジェクトを同じ変数に割り当てると、その割り当てはそのメソッドに対してローカルになります。そのため、myListは変更されません。
Refキーワードを使用して参照型のオブジェクトを渡すと、他のオブジェクトを同じ変数に割り当てることができ、オブジェクト全体が変更されます。
C#は、問題のオブジェクトがICloneable
(明らかにList
クラスは実行しない)を実行しない限り、値渡し時に浅いコピーを実行します。
つまり、List
自体をコピーしますが、リスト内のオブジェクトへの参照は同じままです。つまり、ポインターは元のList
と同じオブジェクトを引き続き参照します。
新しいList
が参照するものの値を変更すると、元のList
も変更されます(同じオブジェクトを参照しているため)。ただし、myList
が完全に参照するものを新しいList
に変更すると、元のList
のみがこれらの整数を参照します。
詳細については、Passing Reference-Type Parametersセクションの このMSDN記事「Passing Parameters」 を参照してください。
「C#で汎用リストを複製する方法」 StackOverflowのリストの詳細コピーの作成方法について説明しています。
誰もが上で言ったことに同意しますが。私はこのコードについて異なる見解を持っています。 基本的に、グローバルではなくローカル変数myListに新しいリストを割り当てます。 ChangeList(List myList)の署名をprivate void ChangeList()に変更すると、3の出力が表示されます。 4。
ここに私の理由があります...リストは参照で渡されますが、値でポインタ変数を渡すと考えてください。ChangeList(myList)を呼び出すと、ポインタは(Global)myListに渡されます。現在、これは(local)myList変数に格納されています。そのため、(ローカル)myListと(グローバル)myListは同じリストを指します。 (ローカル)myListは元の(グローバル)myListを参照しているため、ソートを実行します。次に、新しいリストを作成し、その(ローカル)myListにポインターを割り当てます。しかし、関数が終了するとすぐに(ローカル)myList変数は破棄されます。 HTH
class Test
{
List<int> myList = new List<int>();
public void TestMethod()
{
myList.Add(100);
myList.Add(50);
myList.Add(10);
ChangeList();
foreach (int i in myList)
{
Console.WriteLine(i);
}
}
private void ChangeList()
{
myList.Sort();
List<int> myList2 = new List<int>();
myList2.Add(3);
myList2.Add(4);
myList = myList2;
}
}