System.Array.CopyTo()とSystem.Array.Clone()の違い


82

違いは何だSystem.Array.CopyTo()とはSystem.Array.Clone()


31
面接の質問のようなものです。「手元にあることを思い出せません。ドキュメントを確認させてください...」
CodyGray

@MisterDevどちらも、コピー元の元の配列への参照を保持しません。
Nyerguds 2016年

@Nyergudsどちらも、元の配列オブジェクト自体ではなく、元の配列要素オブジェクトへの参照を保持していることを意味していると思います。
reirab 2016

1
@reirabああ、私は彼が何を意味するのか知っています。しかし、彼が間違っていると言ったことを指摘する必要があると感じました。
Nyerguds 2016

回答:


63

クローン()メソッドは、元の配列内のすべての要素を含む新しい配列(浅いコピー)オブジェクトを返します。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.
編集:

間違った例を削除してください。


6
あなたの例は間違っています。最初のものでnumbersCopyは、に割り当てられた配列への単なる別の参照numbersです。これは、メソッドを使用することと同じではありませんCopyTo()。を使用するとCopyTo()Clone()例と同じ結果が得られます。また、これはC#です-するSystem.out.println必要がありますConsole.WriteLine
グラハムクラーク

6
他の人が言っているように誤解を招くこの答えは、ここからのコピー&ペーストです:geekswithblogs.net/dforhan/archive/2005/12/01/61852.aspx
ミハイル

GenZiyの例によると、どちらも浅いコピーです。配列の浅いコピーは、参照型か値型かに関係なく、配列の要素のみをコピーしますが、参照が参照するオブジェクトはコピーしません。新しい配列の参照は、元の配列の参照が指しているのと同じオブジェクトを指します。対照的に、配列のディープコピーは、要素と、要素によって直接または間接的に参照されるすべてのものをコピーします。 msdn.microsoft.com/en-us/library/system.array.clone.aspx
Mike

@PatrickDesjardins。私にはあまり明確ではありません。両方が浅いコピーの場合、深いコピーとは何ですか。CopyTo()が浅いコピーである理由。
KumarHarsh 2014年

1
.Net 3.5では、LinqのToArray()メソッドは、とにかく配列を浅くクローンするはるかに簡単な(そして型指定された)方法を提供します。配列なので、それでIENumerable<T>動作します。
Nyerguds 2016年

27

これまで言及されていないもう1つの違いは、

  • Clone()新しいものをゼロから作成されるので、コピー先の配列の必要性はまだ存在していません。
  • CopyTo()すでに存在するコピー先の配列の必要性を行うだけでなく、それはあなたが先として指定したインデックスからソース配列内のすべての要素を保持するのに十分な大きさにする必要があります。

22

他の多くの回答で述べられているように、どちらの方法も配列の浅いコピーを実行します。ただし、まだ対処されておらず、次のリストで強調表示されている違いと推奨事項があります。

の特徴System.Array.Clone

  • .NET 4.0を使用したテストでは、CopyToおそらくObject.MemberwiseClone;を使用しているためよりも遅いこと示されています。
  • 結果を適切なタイプにキャストする必要があります。
  • 結果の配列は、ソースと同じ長さです。

の特徴System.Array.CopyTo

  • Clone同じタイプの配列にコピーする場合よりも高速です。
  • それはに呼び出すArray.Copy機能である継承最も有用なものであること、:
    • 値型要素を参照型要素にボックス化できます。たとえば、int[]配列をobject[];にコピーします。
    • 参照型要素を値型要素object[]にボックスint化解除できます。たとえば、ボックス化された配列をint[];にコピーします。
    • 値タイプに対して拡大変換を実行できます。たとえば、をにコピーint[]しますlong[]
    • たとえば、Stream[]配列をにコピーするなど、要素をダウンキャストできますMemoryStream[](ソース配列内のいずれかの要素がMemoryStream例外に変換できない場合はスローされます)。
  • ソースよりも長い長さのターゲット配列にソースをコピーできます。

また、これらのメソッドはICloneableandをサポートできるICollectionようになっているため、配列型の変数を扱う場合は、CloneorCopyToを使用せず、代わりにorを使用するArray.Copy必要がありArray.ConstrainedCopyます。制約付きコピーは、コピー操作が正常に完了できない場合でも、ターゲットアレイの状態が破損しないことを保証します。


これは確かな情報です。では、より高速で汎用的なバージョンのCloneを作成してみませんか?次のようなもの:例:public static T [] ExtFastClone <T>(this T [] arr){if(null == arr){return null; } T [] arr2 =新しいT [arr.Length]; arr.CopyTo(arr2、0); arr2を返します。または、次のようなキャストバージョンを実行できます(int-> longを許可するため)。publicstaticTOut [] ExtFastClone <TIn、TOut>(this TIn [] arr)
kevinarpe 2012

.Net 3.5以降でのベアシャロークローニングの場合は、Linqの.ToArray()方法を使用できます。とにかくコピーを作成し、IEnumerable<>配列を含む任意ので実行できます。そして、とは異なり.Clone()、それはタイプされているので、キャストは必要ありません。
Nyerguds 2016年

21

@PatrickDesjardinsが言ったように、どちらも浅いコピーを実行します(それCopyToが深いコピーを行うと考える多くの誤解された魂にもかかわらず)。

ただし、CopyTo1つの配列を宛先配列の指定されたインデックスにコピーできるため、柔軟性が大幅に向上します。


8
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"

起源


1
おそらく、shalow copyは、値ではなく、参照のみがコピーされることを意味します。したがって、myarray [0]の値を「1」から0に変更する場合は、myarray1 [0]とmyarray [1]の値も0にしないでください。–
Adarsh Kumar

1
申し訳ありませんが、あなたの推測は間違っています。浅いコピーは参照のコピーではありません:「MemberwiseCloneメソッドは、新しいオブジェクトを作成し、現在のオブジェクトの非静的フィールドを新しいオブジェクトにコピーすることによって浅いコピーを作成します。」msdn.microsoft.com/en-us/library/…を
GenZiy 2014年

1
配列に入力する型がプリミティブ/不変である場合、浅いコピーまたは深いコピーは関係ありません。文字列と整数、他の場所に配置されると常に新しいコピーを生成します。ディープコピーをテストするには、複雑なオブジェクト(配列など)をスポットの1つに配置します。
Nyerguds 2016年

2

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()の両方)は最初の(トップ)レベルまで作成されます。ただし、下位レベルはコピーされません。下位レベルのコピーも必要な場合は、明示的に行う必要があります。そのため、参照型要素の複製またはコピー後、複製またはコピーされた配列の各要素は、元の配列の対応する要素によって参照されるのと同じメモリ位置を参照します。これは、下位レベル用に個別のインスタンスが作成されていないことを明確に示しています。その場合、コピーまたはクローン配列の要素の値を変更しても、元の配列の対応する要素には影響しません。

私の説明は網羅的だと思いますが、それを理解できるようにする他の方法は見つかりませんでした。


1

Array.Clone()の配列intまたは文字列を参照としてメソッドに渡すと、技術的に深いコピーが実行されます。

例えば

int[] numbers = new int[] { -11, 12, -42, 0, 1, 90, 68, 6, -9 }; 

SortByAscending(numbers); // Sort the array in ascending order by clone the numbers array to local new array.
SortByDescending(numbers); // Same as Ascending order Clone

メソッドが数値の配列を並べ替えても、並べ替えメソッドに渡される実際の参照には影響しません。つまり、数値配列は、1行目で同じ並べ替えられていない初期形式になります。

注:クローンは、並べ替え方法で実行する必要があります。


0

このClone()メソッドは、ターゲットインスタンスへの参照を提供せず、コピーを提供するだけです。インクルードCopyTo()メソッドは、要素を既存のインスタンスにコピーします。

どちらもターゲットインスタンスの参照を提供せず、多くのメンバーが参照なしで浅いコピー(イリュージョンコピー)を提供すると言っているので、これが重要です。


0

答えは私を混乱させます。浅いコピーと言うとき、これは彼らがまだ同じアドレスを指していることを意味します。つまり、どちらかを変更すると、もう一方も変更されます。

したがって、A = [1,2,3,4]があり、それを複製してB = [1,2,3,4]を取得した場合。ここで、B [0] = 9を変更すると、AはA = [9,2,3,4]になります。あれは正しいですか?


番号。b配列の値を変更すると、そのb配列にのみ影響します。A配列ではありません。
Gomathipriya 2013

整数、文字列、日付などは、参照によってコピーされることはありません。浅いとは「1レベルだけ深い」という意味です。これは、参照型(配列またはその他の複雑なオブジェクト)が引き続き同じオブジェクトを指すことを意味します。プリミティブ/不変タイプではありません。これらは、参照として使用されないように設計されています。
Nyerguds 2016年

浅いコピーは、構造体、文字列、リストなどの複雑なオブジェクトにのみ適用されます。Intまたはdouble配列には、常に深いコピーがあります。
ズアブロス

0

どちらも浅いコピーです。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 */

0

Array.Cloneでは、関数を呼び出すときにターゲット/宛先配列が使用可能である必要はありませんが、Array.CopyToでは宛先配列とインデックスが必要です。


-1

Clone() データ/配列の構造のみをコピーするために使用され、実際のデータはコピーされません。

CopyTo() 構造と実際のデータをコピーします。


-2

注意:String []とStringBuilder []の使用には違いがあります。

文字列内-文字列を変更すると、同じ文字列を指す(CopyToまたはCloneによって)コピーした他の配列は変更されませんが、元の文字列配列は新しい文字列を指しますが、StringBuilderを使用する場合配列では、文字列ポインタは変更されないため、この配列用に作成したすべてのコピーに影響します。例えば:

public void test()
{
    StringBuilder[] sArrOr = new StringBuilder[1];
    sArrOr[0] = new StringBuilder();
    sArrOr[0].Append("hello");
    StringBuilder[] sArrClone = (StringBuilder[])sArrOr.Clone();
    StringBuilder[] sArrCopyTo = new StringBuilder[1];
    sArrOr.CopyTo(sArrCopyTo,0);
    sArrOr[0].Append(" world");

    Console.WriteLine(sArrOr[0] + " " + sArrClone[0] + " " + sArrCopyTo[0]);
    //Outputs: hello world hello world hello world

    //Same result in int[] as using String[]
    int[] iArrOr = new int[2];
    iArrOr[0] = 0;
    iArrOr[1] = 1;
    int[] iArrCopyTo = new int[2];
    iArrOr.CopyTo(iArrCopyTo,0);
    int[] iArrClone = (int[])iArrOr.Clone();
    iArrOr[0]++;
    Console.WriteLine(iArrOr[0] + " " + iArrClone[0] + " " + iArrCopyTo[0]);
   // Output: 1 0 0
}

1
これはCopyTovsとは関係ありませんClone。これは、参照セマンティクスと値セマンティクスの違いです。intは値型であるため、毎回新しいコピーを取得します。StringBuilderには参照セマンティクスがあるため、同じコピーを操作しています。
nawfal 2013

@ nawfal-私が「注意してください」と書いたのはそのためです... copytoとcloneでは、String、StringBuilder、intの動作に違いがあり、それを知らない人にとっては混乱を招く可能性があります。
inbaly 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.