System.Array.CopyTo()
とSystem.Array.Clone()
の違いは何ですか?
Clone()メソッドは、元の配列のすべての要素を含む新しい配列(浅いコピー)オブジェクトを返します。 CopyTo()メソッドは、要素を別の既存の配列にコピーします。どちらも浅いコピーを実行します。浅いコピーとは、コンテンツ(各配列要素)に元の配列の要素と同じオブジェクトへの参照が含まれることを意味します。ディープコピー(これらのメソッドはどちらも実行しません)は、各要素のオブジェクトの新しいインスタンスを作成し、異なるが同一のオブジェクトを作成します。
違いは次のとおりです。
1- CopyTo require to have a destination array when Clone return a new array.
2- CopyTo let you specify an index (if required) to the destination array.
間違った例を削除してください。
これまで言及されていないもう1つの違いは、
Clone()
では、新しい配列が最初から作成されるため、宛先配列はまだ存在する必要はありません。CopyTo()
では、宛先配列が既に存在する必要があるだけでなく、宛先として指定したインデックスからのソース配列のすべての要素を保持するのに十分な大きさである必要があります。@PatrickDesjardinsが言ったように、両方とも浅いコピーを実行します(CopyTo
はディープコピーを行うと考える多くの誤った魂にもかかわらず)。
ただし、CopyTo
を使用すると、1つの配列を宛先配列の指定されたインデックスにコピーできるため、柔軟性が大幅に向上します。
他の多くの回答で述べられているように、両方のメソッドは配列の shallow copys を実行します。ただし、まだ対処されておらず、以下のリストで強調表示されている相違点と推奨事項があります。
System.Array.Clone
の特性:
CopyTo
よりも遅いことが示されています。おそらく Object.MemberwiseClone
;を使用しているためです。System.Array.CopyTo
の特性:
Clone
より高速です。Array.Copy
を呼び出すことは機能です、最も便利なものです:int[]
配列をobject[]
にコピーできます。int
のobject[]
配列をint[]
にコピーできます。int[]
をlong[]
にコピーするなど、値の型に対して拡大変換を実行できます。Stream[]
配列をMemoryStream[]
にコピーできます(ソース配列の要素がMemoryStream
に変換できない場合、例外がスローされます)。また、これらのメソッドは ICloneable
および ICollection
をサポートするために利用できるようになっていることに注意してください。配列型の変数を扱う場合は、Clone
またはCopyTo
を使用せず、代わりに Array.Copy
または Array.ConstrainedCopy
。制約付きコピーにより、コピー操作が正常に完了できない場合でも、ターゲットアレイの状態が破損しないことが保証されます。
object[] myarray = new object[] { "one", 2, "three", 4, "really big number", 2324573984927361 };
//create shallow copy by CopyTo
//You have to instantiate your new array first
object[] myarray2 = new object[myarray.Length];
//but then you can specify how many members of original array you would like to copy
myarray.CopyTo(myarray2, 0);
//create shallow copy by Clone
object[] myarray1;
//here you don't need to instantiate array,
//but all elements of the original array will be copied
myarray1 = myarray.Clone() as object[];
//if not sure that we create a shalow copy lets test it
myarray[0] = 0;
Console.WriteLine(myarray[0]);// print 0
Console.WriteLine(myarray1[0]);//print "one"
Console.WriteLine(myarray2[0]);//print "one"
CopyTo()とClone()はどちらも浅いコピーを作成します。 Clone()メソッドは、元の配列のクローンを作成します。正確な長さの配列を返します。
一方、CopyTo()は、指定された宛先配列インデックスから開始して、元の配列から宛先配列に要素をコピーします。これにより、既存の配列に要素が追加されることに注意してください。
次のコードは、CopyTo()がディープコピーを作成するという投稿と矛盾します。
public class Test
{
public string s;
}
// Write Main() method and within it call test()
private void test()
{
Test[] array = new Test[1];
array[0] = new Test();
array[0].s = "ORIGINAL";
Test[] copy = new Test[1];
array.CopyTo(copy, 0);
// Next line displays "ORIGINAL"
MessageBox.Show("array[0].s = " + array[0].s);
copy[0].s = "CHANGED";
// Next line displays "CHANGED", showing that
// changing the copy also changes the original.
MessageBox.Show("array[0].s = " + array[0].s);
}
少し説明しましょう。配列の要素が参照型の場合、コピー(Clone()とCopyTo()の両方)は最初(トップ)レベルまで作成されます。ただし、下位レベルはコピーされません。下位レベルのコピーも必要な場合は、明示的に行う必要があります。そのため、参照型の要素を複製またはコピーした後、複製またはコピーされた配列の各要素は、元の配列の対応する要素によって参照されるのと同じメモリ位置を参照します。これは、下位レベルに個別のインスタンスが作成されないことを明確に示しています。その場合、コピーまたはクローン配列の要素の値を変更しても、元の配列の対応する要素には影響しません。
私の説明は網羅的であると思いますが、理解できるようにする他の方法は見つけませんでした。
Array.Cloneは、関数を呼び出すときにターゲット/宛先配列を使用可能にする必要はありませんが、Array.CopyToは宛先配列とインデックスを必要とします。
Clone()
メソッドは、コピーを提供するだけでターゲットインスタンスへの参照を提供しません。 CopyTo()
メソッドは、要素を既存のインスタンスにコピーします。
どちらもターゲットインスタンスの参照を提供せず、多くのメンバーが参照なしで浅いコピー(イリュージョンコピー)を提供すると言うので、これがキーです。
どちらも浅いコピーです。 CopyToメソッドはディープコピーではありません。次のコードを確認します。
public class TestClass1
{
public string a = "test1";
}
public static void ArrayCopyClone()
{
TestClass1 tc1 = new TestClass1();
TestClass1 tc2 = new TestClass1();
TestClass1[] arrtest1 = { tc1, tc2 };
TestClass1[] arrtest2 = new TestClass1[arrtest1.Length];
TestClass1[] arrtest3 = new TestClass1[arrtest1.Length];
arrtest1.CopyTo(arrtest2, 0);
arrtest3 = arrtest1.Clone() as TestClass1[];
Console.WriteLine(arrtest1[0].a);
Console.WriteLine(arrtest2[0].a);
Console.WriteLine(arrtest3[0].a);
arrtest1[0].a = "new";
Console.WriteLine(arrtest1[0].a);
Console.WriteLine(arrtest2[0].a);
Console.WriteLine(arrtest3[0].a);
}
/* Output is
test1
test1
test1
new
new
new */
答えは私を混乱させます。浅いコピーと言うとき、これは彼らがまだ同じアドレスを指していることを意味します。つまり、どちらか一方を変更すると、もう一方も変更されます。
したがって、A = [1,2,3,4]があり、それを複製してB = [1,2,3,4]を取得した場合。さて、B [0] = 9を変更すると、AはA = [9,2,3,4]になります。あれは正しいですか?