System.Array.CopyTo ()와 System.Array.Clone ()의 차이점


82

System.Array.CopyTo()과 의 차이점은 무엇입니까 System.Array.Clone()?


31
일종의 멍청한 인터뷰 질문입니다. "기억이 나지 않습니다. 문서를 확인해 보겠습니다 ..."
Cody Gray

@MisterDev 둘 다 복사 한 원본 배열에 대한 참조를 유지하지 않습니다.
Nyerguds

@Nyerguds 나는 그가 원래 배열 객체 자체가 아니라 원래 배열 요소 객체에 대한 참조를 유지한다는 것을 의미한다고 생각합니다.
reirab

1
@reirab 오, 그가 무슨 뜻인지 알고 있습니다. 그러나 나는 그가 틀렸다는 것을 지적 할 필요가 있다고 느꼈다.
Nyerguds

답변:


63

클론 () 메소드는 새로운 어레이 원의 배열에있는 모든 요소를 포함하는 (a 얕은 복사) 객체를 반환한다. 하는 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.
Graham Clark

6
이 답변은 다른 사람이 말했듯 이 오해의 소지 가 있습니다. geekswithblogs.net/dforhan/archive/2005/12/01/61852.aspx
Mikhail

GenZiy의 예에 따르면 둘 다 얕은 사본입니다. Array의 단순 복사본은 참조 유형이든 값 유형이든 관계없이 Array의 요소 만 복사하지만 참조가 참조하는 개체는 복사하지 않습니다. 새 Array의 참조는 원래 Array의 참조가 가리키는 것과 동일한 개체를 가리 킵니다. 대조적으로, Array의 깊은 복사본은 요소와 요소에 의해 직접 또는 간접적으로 참조되는 모든 것을 복사합니다. msdn.microsoft.com/en-us/library/system.array.clone.aspx
Mike

@PatrickDesjardins. 그것은 나에게 명확하지 않습니다. 둘 다 얕은 복사면 그렇다면 깊은 복사는 무엇입니까. 왜 CopyTo ()는 얕은 복사입니다.
KumarHarsh

1
.Net 3.5에서 Linq의 ToArray()방법은 어쨌든 배열을 얕게 복제하는 훨씬 더 간단하고 유형이 지정된 방법을 제공 합니다. 배열이기 때문에 IENumerable<T>작동합니다.
Nyerguds

27

지금까지 언급되지 않은 또 다른 차이점은

  • 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예외 로 변환 할 수 없는 경우 발생).
  • 소스보다 길이가 긴 타겟 스토리지에 소스를 복사 할 수 있습니다.

또한 이러한 방법을 지원하기 위해 사용할 수 있습니다주의 ICloneableICollection당신은 당신이 사용하지 말아야 배열 유형의 변수를 처리하는 그렇다면, Clone또는 CopyTo사용 대신하고 Array.CopyArray.ConstrainedCopy. 제한된 복사는 복사 작업을 성공적으로 완료 할 수없는 경우 대상 스토리지 상태가 손상되지 않도록합니다.


이것은 확실한 정보입니다. 그렇다면 더 빠르고 일반적인 버전의 클론을 작성하지 않는 이유는 무엇입니까? 예 : 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 허용)을 수행 할 수 있습니다. public static TOut [] ExtFastClone <TIn, TOut> (this TIn [] arr)
kevinarpe

.Net 3.5 이상에서 베어 얕은 복제의 경우 Linq의 .ToArray()방법을 사용할 수 있습니다 . 어쨌든 복사본을 만들고 IEnumerable<>배열을 포함한 모든 에서 실행할 수 있습니다 . 그리고와 달리 .Clone()타자기 때문에 캐스팅이 필요하지 않습니다.
Nyerguds

21

둘 다 @PatrickDesjardins가 말한 것처럼 얕은 복사를 수행 CopyTo합니다 (깊은 복사 를한다고 생각하는 많은 오도 된 영혼에도 불구하고 ).

그러나 CopyTo하나의 배열을 대상 배열의 지정된 인덱스에 복사 할 수 있으므로 훨씬 더 많은 유연성이 제공됩니다.


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는 값이 아닌 참조 만 복사한다는 의미입니다. 당신이 다음 myarray1 [0]에서 myArray [1]의 값을에서 myArray [0] "하나"에서 0의 값을 안 변화하고 그래서 경우도 0이
ADARSH 쿠마

1
죄송합니다. 추측이 틀 렸습니다. 단순 복사본은 참조의 복사본이 아닙니다. "MemberwiseClone 메서드는 새 개체를 만든 다음 현재 개체의 비 정적 필드를 새 개체에 복사하여 단순 복사본을 만듭니다." msdn.microsoft.com/en-us/library/…
GenZiy

1
배열에 넣은 유형이 primitive / immutable 인 경우 Shallow 또는 Deep Copy는 관련이 없습니다 . 문자열과 정수 다른 것에 넣을 때 항상 새로운 사본을 생성합니다. 딥 카피를 테스트하려면 스팟 중 하나에 복잡한 객체 (예 : 배열)를 배치합니다.
Nyerguds

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 년

정수, 문자열, 날짜 등 은 참조로 복사되지 않습니다 . Shallow는 "단 한 레벨 깊이"를 의미합니다. 이는 참조 유형 (배열 또는 기타 복잡한 객체)이 여전히 동일한 객체를 가리킴을 의미합니다. 원시 / 불변 유형이 아닙니다. 그것들은 참조로 사용되지 않도록 설계되었습니다.
Nyerguds

얕은 복사본은 구조체, 문자열, 목록 등과 같은 복잡한 개체에만 적용됩니다. Int 또는 double 배열에는 항상 전체 복사본이 있습니다.
Zuabros

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 []로 사용하는 것에는 차이가 있습니다.

String에서-String을 변경하면 동일한 문자열을 가리키는 CopyTo 또는 Clone으로 복사 한 다른 배열은 변경되지 않지만 원래 String 배열은 새 문자열을 가리킬 것입니다. 그러나 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
이것은 CopyTo대 와 관련이 없습니다 Clone. 참조 의미론과 값 의미론 일뿐입니다. int는 값 유형이므로 매번 새 복사본을 얻습니다. StringBuilder에는 참조 의미 체계가 있으므로 동일한 복사본에서 작업하고 있습니다.
nawfal

@nawfal-그게 제가 '알려주세요'라고 쓴 이유입니다 ... String, StringBuilder 및 int, copyto 및 clone 사이에 동작의 차이가 있으며이를 모르는 사람에게는 혼란 스러울 수 있습니다.
inbaly
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.