Sự khác biệt giữa System.Array.CopyTo()
và là System.Array.Clone()
gì?
Sự khác biệt giữa System.Array.CopyTo()
và là System.Array.Clone()
gì?
Câu trả lời:
Phương thức Clone () trả về một đối tượng mảng mới (một bản sao cạn) chứa tất cả các phần tử trong mảng ban đầu. Phương thức CopyTo () sao chép các phần tử vào một mảng hiện có khác. Cả hai đều thực hiện một bản sao nông. Bản sao cạn có nghĩa là nội dung (mỗi phần tử mảng) chứa các tham chiếu đến cùng một đối tượng như các phần tử trong mảng ban đầu. Một bản sao sâu (mà cả hai phương thức này đều không thực hiện) sẽ tạo ra một thể hiện mới của đối tượng của mỗi phần tử, dẫn đến một đối tượng khác nhưng giống hệt nhau.
Vì vậy, sự khác biệt là:
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.
Biên tập:
Loại bỏ ví dụ sai.
numbersCopy
chỉ là một tham chiếu khác đến mảng được gán cho numbers
. Điều này không giống như sử dụng CopyTo()
phương pháp. Nếu bạn sử dụng CopyTo()
, bạn sẽ nhận được kết quả tương tự như trong Clone()
ví dụ của bạn . Ngoài ra, đây là C # - System.out.println
nên được Console.WriteLine
.
ToArray()
phương thức của Linq cung cấp một cách đơn giản hơn nhiều (và được đánh máy ) để sao chép nông một mảng. Kể từ khi Array IENumerable<T>
hoạt động trên nó.
Một sự khác biệt khác chưa được đề cập cho đến nay là
Clone()
mảng đích không cần tồn tại vì một mảng mới được tạo từ đầu.CopyTo()
không chỉ mảng đích cần đã tồn tại mà còn cần phải đủ lớn để chứa tất cả các phần tử trong mảng nguồn từ chỉ mục bạn chỉ định làm đích.Như đã nêu trong nhiều câu trả lời khác, cả hai phương thức đều thực hiện các bản sao cạn của mảng. Tuy nhiên, có những khác biệt và khuyến nghị vẫn chưa được giải quyết và được đánh dấu trong danh sách sau.
Đặc điểm của System.Array.Clone
:
CopyTo
có thể là do nó sử dụng Object.MemberwiseClone
;Đặc điểm của System.Array.CopyTo
:
Clone
khi sao chép vào mảng cùng loại;Array.Copy
kế thừa là các khả năng , là những khả năng hữu ích nhất:
int[]
mảng vào một object[]
;object[]
mảng được đóng hộp int
thành một int[]
;int[]
thành a long[]
.Stream[]
mảng vào một MemoryStream[]
(nếu bất kỳ phần tử nào trong mảng nguồn không thể chuyển đổi thành MemoryStream
một ngoại lệ sẽ được ném).Cũng lưu ý, các phương thức này được tạo sẵn để hỗ trợ ICloneable
và ICollection
, vì vậy nếu bạn đang xử lý các biến của kiểu mảng, bạn không nên sử dụng Clone
hoặc CopyTo
và thay vào đó hãy sử dụng Array.Copy
hoặc Array.ConstrainedCopy
. Bản sao bị ràng buộc đảm bảo rằng nếu thao tác sao chép không thể hoàn tất thành công thì trạng thái mảng đích không bị hỏng.
.ToArray()
phương pháp của Linq . Nó vẫn tạo ra một bản sao và nó có thể được thực thi trên bất kỳ IEnumerable<>
, bao gồm cả mảng. Và không giống như .Clone()
, nó được đánh máy, vì vậy không cần truyền.
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"
Cả CopyTo () và Clone () đều tạo bản sao cạn. Phương thức clone () tạo bản sao của mảng ban đầu. Nó trả về một mảng độ dài chính xác.
Mặt khác, CopyTo () sao chép các phần tử từ mảng ban đầu sang mảng đích bắt đầu từ chỉ số mảng đích đã chỉ định. Lưu ý rằng, điều này thêm các phần tử vào một mảng đã tồn tại.
Đoạn mã sau sẽ mâu thuẫn với các bài đăng nói rằng CopyTo () tạo một bản sao sâu:
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);
}
Để tôi giải thích một chút. Nếu các phần tử của mảng thuộc loại tham chiếu, thì bản sao (cả cho Clone () và CopyTo ()) sẽ được tạo ở mức đầu tiên (trên cùng). Nhưng cấp độ thấp hơn không bị sao chép. Nếu chúng ta cũng cần bản sao của cấp thấp hơn, chúng ta phải làm điều đó một cách rõ ràng. Đó là lý do tại sao sau khi Sao chép hoặc Sao chép các phần tử kiểu tham chiếu, mỗi phần tử trong mảng được Sao chép hoặc Sao chép tham chiếu đến cùng một vị trí bộ nhớ như được tham chiếu bởi phần tử tương ứng trong mảng ban đầu. Điều này chỉ ra rõ ràng rằng không có trường hợp riêng biệt nào được tạo cho cấp thấp hơn. Và nếu đúng như vậy thì việc thay đổi giá trị của bất kỳ phần tử nào trong mảng được Sao chép hoặc Nhân bản sẽ không có hiệu lực trong phần tử tương ứng của mảng ban đầu.
Tôi nghĩ rằng lời giải thích của tôi là đầy đủ nhưng tôi không tìm thấy cách nào khác để làm cho nó dễ hiểu.
Array.Clone()
sẽ thực hiện sao chép sâu về mặt kỹ thuật, khi chuyển mảng int
hoặc chuỗi tới một phương thức làm tham chiếu.
Ví dụ
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
Ngay cả khi các phương thức sắp xếp mảng số nhưng nó sẽ không ảnh hưởng đến tham chiếu thực tế được truyền đến các phương thức sắp xếp. Ví dụ mảng số sẽ có cùng định dạng ban đầu không được sắp xếp ở dòng số 1.
Lưu ý: Bản sao nên được thực hiện trong các phương pháp sắp xếp.
Các Clone()
phương pháp không cho tham chiếu đến dụ mục tiêu chỉ cung cấp cho bạn một bản sao. cácCopyTo()
phương pháp bản sao các yếu tố vào một thể hiện.
Cả hai đều không cung cấp tham chiếu của cá thể đích và như nhiều thành viên nói rằng họ cung cấp bản sao nông (bản sao ảo) mà không có tham chiếu, đây là chìa khóa.
Câu trả lời là khó hiểu đối với tôi. Khi bạn nói bản sao cạn, điều này có nghĩa là họ vẫn đang trỏ đến cùng một địa chỉ. Có nghĩa là, thay đổi cái này cũng sẽ thay đổi cái khác.
Vì vậy, nếu tôi có A = [1,2,3,4] và tôi sao chép nó và nhận được B = [1,2,3,4]. Bây giờ, nếu tôi thay đổi B [0] = 9. Điều này có nghĩa là A bây giờ sẽ là A = [9,2,3,4]. Đúng không?
Cả hai đều là bản sao nông cạn. Phương thức CopyTo không phải là một bản sao sâu. Kiểm tra mã sau:
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 */
Array.Clone không yêu cầu một mảng đích / đích khả dụng khi gọi hàm, trong khi Array.CopyTo yêu cầu một mảng đích và một chỉ mục.
Clone()
được sử dụng để chỉ sao chép cấu trúc của dữ liệu / mảng, nó không sao chép dữ liệu thực tế.
CopyTo()
sao chép cấu trúc cũng như dữ liệu thực tế.
Xin lưu ý: Có sự khác biệt giữa việc sử dụng String [] đến StringBuilder [].
Trong Chuỗi - nếu bạn thay đổi Chuỗi, các mảng khác mà chúng tôi đã sao chép (bằng CopyTo hoặc Clone) trỏ đến cùng một chuỗi sẽ không thay đổi, nhưng mảng Chuỗi ban đầu sẽ trỏ đến một Chuỗi mới, tuy nhiên, nếu chúng ta sử dụng StringBuilder trong một mảng, con trỏ chuỗi sẽ không thay đổi, do đó, nó sẽ ảnh hưởng đến tất cả các bản sao chúng ta đã tạo cho mảng này. Ví dụ:
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
}
CopyTo
vs Clone
. Nó chỉ là ngữ nghĩa tham chiếu so với ngữ nghĩa giá trị. int là một kiểu giá trị, vì vậy bạn luôn nhận được một bản sao mới. StringBuilder có ngữ nghĩa tham chiếu, vì vậy bạn đang hành động trên cùng một bản sao.