Saya memiliki daftar umum objek di C #, dan ingin mengkloning daftar. Item dalam daftar dapat dikloning, tetapi sepertinya tidak ada pilihan untuk dilakukan list.Clone().
@orip. Bukankah clone()definisi salinan dalam? Dalam C # Anda dapat mengoper pointer dengan mudah dengan =, saya pikir.
Chris
13
@ Chris menyalin salinan dangkal satu tingkat lebih dalam dari salinan pointer. Misalnya salinan daftar yang dangkal akan memiliki elemen yang sama, tetapi akan menjadi daftar yang berbeda.
Saya pikir List.ConvertAll mungkin melakukan ini dalam waktu yang lebih cepat, karena ia dapat pra-mengalokasikan seluruh array untuk daftar, dibandingkan harus mengubah ukuran sepanjang waktu.
MichaelGG
2
@MichaelGG, bagaimana jika Anda tidak ingin Mengkonversi tetapi hanya Mengkloning / Menduplikasi item dalam daftar? Apakah ini akan berhasil? || var clonedList = ListOfStrings.ConvertAll (p => p);
IbrarMumtaz
29
@IbrarMumtaz: Itu sama dengan var clonedList = Daftar baru <string> (ListOfStrings);
Brandon Arnold
4
Solusi bagus! Ngomong-ngomong, saya lebih suka Daftar statis publik <T> CLone <T> ... Ini lebih berguna dalam kasus-kasus seperti ini, karena tidak diperlukan pemeran lebih lanjut: Daftar <MyType> dikloning = listToClone.Clone ();
Plutoz
2
ini kloning yang dalam
George Birbilis
513
Jika elemen Anda adalah tipe nilai, maka Anda bisa melakukannya:
Namun, jika mereka adalah tipe referensi dan Anda ingin salinan yang dalam (dengan asumsi elemen Anda diterapkan dengan benar ICloneable), Anda bisa melakukan sesuatu seperti ini:
Secara pribadi, saya akan menghindari ICloneablekarena kebutuhan untuk menjamin salinan yang mendalam dari semua anggota. Sebagai gantinya, saya menyarankan copy-constructor atau metode pabrik seperti YourType.CopyFrom(YourType itemToCopy)itu mengembalikan contoh baru YourType.
Opsi-opsi ini dapat dibungkus dengan metode (ekstensi atau lainnya).
Saya pikir List <T> .ConvertAll mungkin terlihat lebih bagus daripada membuat daftar baru dan melakukan foreach + add.
MichaelGG
2
@ Dimitri: Tidak, itu tidak benar. Masalahnya adalah, ketika ICloneabledidefinisikan, definisi tidak pernah menyatakan apakah klon itu dalam atau dangkal, jadi Anda tidak dapat menentukan jenis operasi Klon yang akan dilakukan ketika suatu objek mengimplementasikannya. Ini berarti bahwa jika Anda ingin melakukan kloning yang mendalam List<T>, Anda harus melakukannya tanpa ICloneablememastikan itu adalah salinan yang dalam.
Jeff Yates
5
Mengapa tidak menggunakan metode AddRange? ( newList.AddRange(oldList.Select(i => i.Clone())atau newList.AddRange(oldList.Select(i => new YourType(i))
phoog
5
@phoog: Saya pikir itu sedikit kurang dapat dibaca / dimengerti ketika memindai kode, itu saja. Keterbacaan menang untuk saya.
Jeff Yates
1
@ JeffYates: Satu kerutan yang dianggap tidak cukup adalah bahwa hal-hal yang umumnya hanya perlu disalin jika ada beberapa jalur eksekusi yang akan memutasi mereka. Ini sangat umum untuk memiliki jenis kekal memegang referensi ke sebuah contoh dari jenis bisa berubah, tetapi tidak pernah mengekspos contoh bahwa untuk apa pun yang akan bermutasi itu. Penyalinan yang tidak perlu dari hal-hal yang tidak akan pernah berubah kadang-kadang dapat menguras kinerja utama , meningkatkan penggunaan memori dengan urutan besarnya.
supercat
84
Untuk salinan yang dangkal, Anda bisa menggunakan metode GetRange dari kelas Daftar generik.
Anda juga dapat mencapainya dengan menggunakan kontruktor Daftar <T> untuk menentukan Daftar <T> yang digunakan untuk menyalin. misalnya var shallowClonedList = Daftar baru <MyObject> (originalList);
Arkiliknam
9
Saya sering menggunakan List<int> newList = oldList.ToList(). Efek yang sama. Namun, solusi Arkiliknam adalah yang terbaik untuk keterbacaan menurut saya.
Dan Bechard
82
publicstaticobjectDeepClone(object obj){object objResult =null;
using (MemoryStream ms =newMemoryStream()){BinaryFormatter bf =newBinaryFormatter();
bf.Serialize(ms, obj);
ms.Position=0;
objResult = bf.Deserialize(ms);}return objResult;}
Ini adalah salah satu cara untuk melakukannya dengan C # dan .NET 2.0. Objek Anda harus seperti itu [Serializable()]. Tujuannya adalah untuk kehilangan semua referensi dan membangun yang baru.
+1 - saya suka jawaban ini - cepat, kotor, tidak menyenangkan, dan sangat efektif. Saya menggunakan silverlight, dan menggunakan DataContractSerializer karena BinarySerializer tidak tersedia. Siapa yang perlu menulis halaman kode kloning objek ketika Anda bisa melakukan ini? :)
slugster
3
Saya suka ini. Meskipun senang melakukan hal-hal "benar", cepat dan kotor sering kali berguna.
Odrade
3
Cepat! tapi: Kenapa kotor?
raiserle
2
Ini klon yang dalam dan cepat dan mudah. Hati-hati dengan saran lain di halaman ini. Saya mencoba beberapa dan mereka tidak mengkloning dalam.
RandallTo
2
Hanya aspek negatifnya, jika Anda bisa menyebutnya begitu, adalah bahwa kelas Anda harus ditandai Serializable agar ini berfungsi.
Tuukka Haapaniemi
30
Untuk mengkloning daftar, panggil saja. Daftar (). Ini menciptakan salinan yang dangkal.
Microsoft(R)Roslyn C# Compiler version 2.3.2.62116Loading context from'CSharpInteractive.rsp'.Type"#help"for more information.>var x =newList<int>(){3,4};>var y = x.ToList();> x.Add(5)> x
List<int>(3){3,4,5}> y
List<int>(2){3,4}>
Peringatan kecil ini adalah salinan dangkal ... Ini akan membuat dua objek daftar, tetapi objek di dalamnya akan sama. Yaitu mengubah satu properti akan mengubah objek / properti yang sama dalam daftar asli.
Mark G
22
Setelah sedikit modifikasi, Anda juga dapat mengkloning:
publicstatic T DeepClone<T>(T obj){
T objResult;
using (MemoryStream ms =newMemoryStream()){BinaryFormatter bf =newBinaryFormatter();
bf.Serialize(ms, obj);
ms.Position=0;
objResult =(T)bf.Deserialize(ms);}return objResult;}
Jangan lupa T harus berseri, jika tidak Anda mendapatkan System.Runtime.Serialization.SerializationException.
Bence Végert
Jawaban yang bagus. Satu petunjuk: Anda bisa menambahkan if (!obj.GetType().IsSerializable) return default(T);sebagai pernyataan pertama yang mencegah pengecualian. Dan jika Anda mengubahnya ke metode ekstensi, Anda bahkan bisa menggunakan operator Elvis seperti var b = a?.DeepClone();(diberikan var a = new List<string>() { "a", "b" }; misalnya).
Matt
15
Kecuali jika Anda membutuhkan tiruan aktual dari setiap objek di dalam diri Anda List<T>, cara terbaik untuk mengkloning daftar adalah dengan membuat daftar baru dengan daftar lama sebagai parameter koleksi.
Saya setuju dengan user49126, saya melihat bahwa itu adalah salinan dangkal dan perubahan yang dibuat untuk satu daftar tercermin dalam daftar lainnya.
Seidleroni
1
@ Seidleroni, Anda salah. Perubahan yang dilakukan pada daftar yang terpengaruh pada daftar lainnya, perubahan dalam daftar itu sendiri tidak.
Wellington Zanelli
Ini adalah salinan dangkal.
Elliot Chen
Bagaimana ini salinan dangkal?
mko
2
@WellingtonZanelli Baru saja mengkonfirmasi bahwa menghapus elemen dari myList juga menghapusnya dari cloneOfMyList.
Nick Gallimore
13
Gunakan AutoMapper (atau pemetaan pemetaan apa pun yang Anda inginkan) untuk mengkloning itu sederhana dan banyak yang bisa dipertahankan.
Mungkin bukan cara yang paling efisien untuk melakukannya, tetapi kecuali Anda melakukannya 100-an dari 1000-an kali Anda bahkan mungkin tidak melihat perbedaan kecepatan.
Ini bukan tentang perbedaan kecepatan, ini tentang keterbacaan. Jika saya sampai pada baris kode ini, saya akan menampar kepala saya dan bertanya-tanya mengapa mereka memperkenalkan perpustakaan pihak ketiga untuk diserialisasi dan kemudian membatalkan registrasi objek yang saya tidak tahu mengapa itu terjadi. Juga, ini tidak akan berfungsi untuk daftar model dengan objek yang memiliki struktur lingkaran.
Jonathon Cwik
1
Kode ini bekerja sangat baik bagi saya untuk kloning yang dalam. Aplikasi ini memigrasi boilerplate dokumen dari Dev ke QA ke Prod. Setiap objek adalah paket dari beberapa objek templat dokumen, dan setiap dokumen pada gilirannya terdiri dari daftar objek paragraf. Kode ini izinkan saya membuat serialisasi objek .NET "source" dan segera membatalkan deserialisasi objek-objek "target" baru, yang kemudian disimpan ke database SQL di lingkungan yang berbeda. Setelah banyak penelitian, saya menemukan banyak barang, banyak yang terlalu rumit, dan memutuskan untuk mencoba ini. Pendekatan singkat dan fleksibel ini "tepat"!
Teman saya Gregor Martinovic dan saya datang dengan solusi mudah ini menggunakan JavaScript Serializer. Tidak perlu menandai kelas sebagai Serializable dan dalam pengujian kami menggunakan Newtonsoft JsonSerializer bahkan lebih cepat daripada menggunakan BinaryFormatter. Dengan metode ekstensi dapat digunakan pada setiap objek.
Opsi .NET JavascriptSerializer standar:
publicstatic T DeepCopy<T>(this T value){JavaScriptSerializer js =newJavaScriptSerializer();string json = js.Serialize(value);return js.Deserialize<T>(json);}
Saya akan beruntung jika ada yang pernah membaca ini ... tetapi untuk tidak mengembalikan daftar objek tipe dalam metode Clone saya, saya membuat antarmuka:
publicinterfaceIMyCloneable<T>{
T Clone();}
Lalu saya tentukan ekstensi:
publicstaticList<T>Clone<T>(thisList<T> listToClone)where T :IMyCloneable<T>{return listToClone.Select(item =>(T)item.Clone()).ToList();}
Dan ini adalah implementasi dari antarmuka di perangkat lunak penandaan A / V saya. Saya ingin agar metode Clone () saya mengembalikan daftar VidMark (sedangkan antarmuka ICloneable ingin metode saya mengembalikan daftar objek):
privateList<VidMark>_VidMarks;privateList<VidMark>_UndoVidMarks;//Other methods instantiate and fill the listsprivatevoidSetUndoVidMarks(){_UndoVidMarks=_VidMarks.Clone();}
Anda juga bisa dengan mudah mengonversi daftar menjadi array menggunakan ToArray, dan kemudian mengkloning array menggunakan Array.Clone(...). Tergantung pada kebutuhan Anda, metode yang termasuk dalam kelas Array dapat memenuhi kebutuhan Anda.
Ini tidak bekerja; perubahan nilai dalam array yang dikloning MASIH mengubah nilai dalam daftar asli.
Bernoulli Lizard
Anda dapat menggunakan var clonedList = ListOfStrings.ConvertAll (p => p); seperti yang diberikan oleh @IbrarMumtaz .... Berfungsi secara efektif ... Perubahan pada satu daftar disimpan untuk dirinya sendiri dan tidak mencerminkan yang lain
zainul
2
Anda dapat menggunakan metode ekstensi:
namespace extension
{publicclass ext
{publicstaticList<double> clone(thisList<double> t){List<double> kop =newList<double>();int x;for(x =0; x < t.Count; x++){
kop.Add(t[x]);}return kop;}};}
Anda dapat mengkloning semua objek dengan menggunakan anggota tipe nilai mereka misalnya, pertimbangkan kelas ini:
publicclass matrix
{publicList<List<double>> mat;publicint rows,cols;public matrix clone(){// create new object
matrix copy =new matrix();// firstly I can directly copy rows and cols because they are value types
copy.rows =this.rows;
copy.cols =this.cols;// but now I can no t directly copy mat because it is not value type soint x;// I assume I have clone method for List<double>for(x=0;x<this.mat.count;x++){
copy.mat.Add(this.mat[x].clone());}// then mat is clonedreturn copy;// and copy of original is returned }};
Catatan: jika Anda melakukan perubahan apa pun pada salinan (atau kloning) itu tidak akan mempengaruhi objek asli.
tampaknya beberapa koleksi (misalnya DataGrid's SelectedItems at Silverlight) melewatkan implementasi CopyTo yang merupakan masalah dengan pendekatan ini
George Birbilis
1
Saya menggunakan automapper untuk menyalin objek. Saya baru saja mengatur pemetaan yang memetakan satu objek ke dirinya sendiri. Anda dapat membungkus operasi ini dengan cara apa pun yang Anda suka.
Untuk salinan yang dalam, ICloneable adalah solusi yang tepat, tetapi inilah pendekatan yang mirip dengan ICloneable menggunakan konstruktor alih-alih antarmuka ICloneable.
publicclassStudent{publicStudent(Student student){FirstName= student.FirstName;LastName= student.LastName;}publicstringFirstName{get;set;}publicstringLastName{get;set;}}// wherever you have the listList<Student> students;// and then where you want to make a copyList<Student> copy = students.Select(s =>newStudent(s)).ToList();
Anda memerlukan pustaka berikut tempat Anda membuat salinannya
using System.Linq
Anda juga bisa menggunakan for for bukan System.Linq, tetapi Linq membuatnya ringkas dan bersih. Anda juga dapat melakukan seperti yang disarankan oleh jawaban lain dan membuat metode penyuluhan, dll., Tetapi tidak ada yang diperlukan.
Itu disebut "copy constructor". Itu pendekatan yang rawan kesalahan, setiap kali Anda menambahkan bidang baru ke Siswa, Anda harus ingat untuk menambahkannya ke copy constructor. Gagasan utama di balik "klon" adalah untuk menghindari masalah itu.
kenno
2
Bahkan dengan ICloneable, Anda harus memiliki metode "Klon" di kelas Anda. Kecuali Anda menggunakan refleksi (yang juga bisa Anda gunakan dalam pendekatan di atas), metode Clone akan terlihat sangat mirip dengan pendekatan copy constructor di atas, dan akan mengalami masalah yang sama karena harus memperbarui bidang baru / yang diubah. Tetapi itu mengatakan "Kelas harus diperbarui ketika bidang kelas berubah". Tentu saja;)
ztorstri
0
Kode berikut harus ditransfer ke daftar dengan perubahan minimal.
Pada dasarnya ini bekerja dengan memasukkan nomor acak baru dari rentang yang lebih besar dengan setiap loop berturut-turut. Jika sudah ada angka yang sama atau lebih tinggi dari itu, pindahkan angka-angka acak ke atas sehingga mereka mentransfer ke kisaran indeks acak baru yang lebih besar.
// Example Usageint[] indexes = getRandomUniqueIndexArray(selectFrom.Length, toSet.Length);for(int i =0; i < toSet.Length; i++)
toSet[i]= selectFrom[indexes[i]];privateint[] getRandomUniqueIndexArray(int length,int count){if(count > length || count <1|| length <1)returnnewint[0];int[] toReturn =newint[count];if(count == length){for(int i =0; i < toReturn.Length; i++) toReturn[i]= i;return toReturn;}Random r =newRandom();int startPos = count -1;for(int i = startPos; i >=0; i--){int index = r.Next(length - i);for(int j = startPos; j > i; j--)if(toReturn[j]>= index)
toReturn[j]++;
toReturn[i]= index;}return toReturn;}
Hal lain: Anda bisa menggunakan refleksi. Jika Anda akan menembolok ini dengan benar, maka itu akan mengklon 1.000.000 objek dalam 5,6 detik (sayangnya, 16,4 detik dengan objek dalam).
[ProtoContract(ImplicitFields=ImplicitFields.AllPublic)]publicclassPerson{...JobJobDescription...}[ProtoContract(ImplicitFields=ImplicitFields.AllPublic)]publicclassJob{...}privatestaticreadonlyType stringType =typeof(string);publicstaticclassCopyFactory{staticreadonlyDictionary<Type,PropertyInfo[]>ProperyList=newDictionary<Type,PropertyInfo[]>();privatestaticreadonlyMethodInfoCreateCopyReflectionMethod;staticCopyFactory(){CreateCopyReflectionMethod=typeof(CopyFactory).GetMethod("CreateCopyReflection",BindingFlags.Static|BindingFlags.Public);}publicstatic T CreateCopyReflection<T>(T source)where T :new(){var copyInstance =new T();var sourceType =typeof(T);PropertyInfo[] propList;if(ProperyList.ContainsKey(sourceType))
propList =ProperyList[sourceType];else{
propList = sourceType.GetProperties(BindingFlags.Public|BindingFlags.Instance);ProperyList.Add(sourceType, propList);}foreach(var prop in propList){varvalue= prop.GetValue(source,null);
prop.SetValue(copyInstance,value!=null&& prop.PropertyType.IsClass&& prop.PropertyType!= stringType ?CreateCopyReflectionMethod.MakeGenericMethod(prop.PropertyType).Invoke(null,newobject[]{value}):value,null);}return copyInstance;}
Saya mengukurnya dengan cara yang sederhana, dengan menggunakan kelas Watcher.
var person =newPerson{...};for(var i =0; i <1000000; i++){
personList.Add(person);}var watcher =newStopwatch();
watcher.Start();var copylist = personList.Select(CopyFactory.CreateCopyReflection).ToList();
watcher.Stop();var elapsed = watcher.Elapsed;
HASIL: Dengan objek dalam PersonInstance - 16.4, PersonInstance = null - 5.6
CopyFactory hanyalah kelas pengujian saya di mana saya memiliki selusin tes termasuk penggunaan ekspresi. Anda bisa menerapkan ini dalam bentuk lain dalam ekstensi atau apa pun. Jangan lupa tentang caching.
Saya belum menguji serialisasi, tapi saya ragu dengan peningkatan dengan sejuta kelas. Saya akan mencoba sesuatu protobuf cepat / newton.
PS: Demi membaca kesederhanaan, saya hanya menggunakan properti otomatis di sini. Saya dapat memperbarui dengan FieldInfo, atau Anda harus dengan mudah mengimplementasikannya sendiri.
Saya baru-baru ini menguji serializer Protokol Buffer dengan fungsi DeepClone di luar kotak. Ia menang dengan 4,2 detik pada sejuta objek sederhana, tetapi ketika sampai pada objek dalam, ia menang dengan hasil 7,4 detik.
Serializer.DeepClone(personList);
RINGKASAN: Jika Anda tidak memiliki akses ke kelas, maka ini akan membantu. Kalau tidak, itu tergantung pada jumlah objek. Saya pikir Anda bisa menggunakan refleksi hingga 10.000 objek (mungkin sedikit kurang), tetapi untuk lebih dari ini serializer Protokol Buffer akan tampil lebih baik.
Ada cara sederhana untuk mengkloning objek di C # menggunakan serializer dan deserializer JSON.
Anda dapat membuat kelas ekstensi:
using Newtonsoft.Json;staticclass typeExtensions
{[Extension()]publicstatic T jsonCloneObject<T>(T source){string json =JsonConvert.SerializeObject(source);returnJsonConvert.DeserializeObject<T>(json);}}
clone()
definisi salinan dalam? Dalam C # Anda dapat mengoper pointer dengan mudah dengan =, saya pikir.Jawaban:
Anda dapat menggunakan metode ekstensi.
sumber
Jika elemen Anda adalah tipe nilai, maka Anda bisa melakukannya:
Namun, jika mereka adalah tipe referensi dan Anda ingin salinan yang dalam (dengan asumsi elemen Anda diterapkan dengan benar
ICloneable
), Anda bisa melakukan sesuatu seperti ini:Jelas, ganti
ICloneable
generik di atas dan gunakan dengan apa pun jenis elemen Anda yang mengimplementasikanICloneable
.Jika tipe elemen Anda tidak mendukung
ICloneable
tetapi memang memiliki copy-constructor, Anda bisa melakukan ini sebagai gantinya:Secara pribadi, saya akan menghindari
ICloneable
karena kebutuhan untuk menjamin salinan yang mendalam dari semua anggota. Sebagai gantinya, saya menyarankan copy-constructor atau metode pabrik sepertiYourType.CopyFrom(YourType itemToCopy)
itu mengembalikan contoh baruYourType
.Opsi-opsi ini dapat dibungkus dengan metode (ekstensi atau lainnya).
sumber
ICloneable
didefinisikan, definisi tidak pernah menyatakan apakah klon itu dalam atau dangkal, jadi Anda tidak dapat menentukan jenis operasi Klon yang akan dilakukan ketika suatu objek mengimplementasikannya. Ini berarti bahwa jika Anda ingin melakukan kloning yang mendalamList<T>
, Anda harus melakukannya tanpaICloneable
memastikan itu adalah salinan yang dalam.newList.AddRange(oldList.Select(i => i.Clone())
ataunewList.AddRange(oldList.Select(i => new YourType(i)
)Untuk salinan yang dangkal, Anda bisa menggunakan metode GetRange dari kelas Daftar generik.
Dikutip dari: Resep Generik
sumber
List<int> newList = oldList.ToList()
. Efek yang sama. Namun, solusi Arkiliknam adalah yang terbaik untuk keterbacaan menurut saya.Ini adalah salah satu cara untuk melakukannya dengan C # dan .NET 2.0. Objek Anda harus seperti itu
[Serializable()]
. Tujuannya adalah untuk kehilangan semua referensi dan membangun yang baru.sumber
Untuk mengkloning daftar, panggil saja. Daftar (). Ini menciptakan salinan yang dangkal.
sumber
Setelah sedikit modifikasi, Anda juga dapat mengkloning:
sumber
if (!obj.GetType().IsSerializable) return default(T);
sebagai pernyataan pertama yang mencegah pengecualian. Dan jika Anda mengubahnya ke metode ekstensi, Anda bahkan bisa menggunakan operator Elvis sepertivar b = a?.DeepClone();
(diberikanvar a = new List<string>() { "a", "b" };
misalnya).Kecuali jika Anda membutuhkan tiruan aktual dari setiap objek di dalam diri Anda
List<T>
, cara terbaik untuk mengkloning daftar adalah dengan membuat daftar baru dengan daftar lama sebagai parameter koleksi.Perubahan
myList
seperti menyisipkan atau menghapus tidak akan memengaruhicloneOfMyList
dan sebaliknya.Objek aktual kedua Daftar berisi masih sama namun.
sumber
Gunakan AutoMapper (atau pemetaan pemetaan apa pun yang Anda inginkan) untuk mengkloning itu sederhana dan banyak yang bisa dipertahankan.
Tentukan pemetaan Anda:
Lakukan keajaiban:
sumber
Jika Anda hanya peduli tentang jenis nilai ...
Dan Anda tahu tipenya:
Jika Anda tidak tahu jenisnya sebelumnya, Anda akan membutuhkan fungsi pembantu:
Yang adil:
sumber
Jika Anda telah mereferensikan Newtonsoft.Json dalam proyek Anda dan objek Anda serial, Anda selalu dapat menggunakan:
Mungkin bukan cara yang paling efisien untuk melakukannya, tetapi kecuali Anda melakukannya 100-an dari 1000-an kali Anda bahkan mungkin tidak melihat perbedaan kecepatan.
sumber
sumber
sumber
sumber
Teman saya Gregor Martinovic dan saya datang dengan solusi mudah ini menggunakan JavaScript Serializer. Tidak perlu menandai kelas sebagai Serializable dan dalam pengujian kami menggunakan Newtonsoft JsonSerializer bahkan lebih cepat daripada menggunakan BinaryFormatter. Dengan metode ekstensi dapat digunakan pada setiap objek.
Opsi .NET JavascriptSerializer standar:
Opsi lebih cepat menggunakan Newtonsoft JSON :
sumber
sumber
Saya akan beruntung jika ada yang pernah membaca ini ... tetapi untuk tidak mengembalikan daftar objek tipe dalam metode Clone saya, saya membuat antarmuka:
Lalu saya tentukan ekstensi:
Dan ini adalah implementasi dari antarmuka di perangkat lunak penandaan A / V saya. Saya ingin agar metode Clone () saya mengembalikan daftar VidMark (sedangkan antarmuka ICloneable ingin metode saya mengembalikan daftar objek):
Dan akhirnya, penggunaan ekstensi di dalam kelas:
Adakah yang menyukainya? Adakah perbaikan?
sumber
Anda juga bisa dengan mudah mengonversi daftar menjadi array menggunakan
ToArray
, dan kemudian mengkloning array menggunakanArray.Clone(...)
. Tergantung pada kebutuhan Anda, metode yang termasuk dalam kelas Array dapat memenuhi kebutuhan Anda.sumber
Anda dapat menggunakan metode ekstensi:
Anda dapat mengkloning semua objek dengan menggunakan anggota tipe nilai mereka misalnya, pertimbangkan kelas ini:
Catatan: jika Anda melakukan perubahan apa pun pada salinan (atau kloning) itu tidak akan mempengaruhi objek asli.
sumber
Jika Anda membutuhkan daftar yang dikloning dengan kapasitas yang sama, Anda dapat mencoba ini:
sumber
Saya telah membuat sendiri beberapa ekstensi yang mengubah ICollection item yang tidak menerapkan IClonable
sumber
Saya menggunakan automapper untuk menyalin objek. Saya baru saja mengatur pemetaan yang memetakan satu objek ke dirinya sendiri. Anda dapat membungkus operasi ini dengan cara apa pun yang Anda suka.
http://automapper.codeplex.com/
sumber
Menggunakan gips mungkin bermanfaat, dalam hal ini, untuk salinan dangkal:
diterapkan ke daftar umum:
sumber
Untuk salinan yang dalam, ICloneable adalah solusi yang tepat, tetapi inilah pendekatan yang mirip dengan ICloneable menggunakan konstruktor alih-alih antarmuka ICloneable.
Anda memerlukan pustaka berikut tempat Anda membuat salinannya
Anda juga bisa menggunakan for for bukan System.Linq, tetapi Linq membuatnya ringkas dan bersih. Anda juga dapat melakukan seperti yang disarankan oleh jawaban lain dan membuat metode penyuluhan, dll., Tetapi tidak ada yang diperlukan.
sumber
Kode berikut harus ditransfer ke daftar dengan perubahan minimal.
Pada dasarnya ini bekerja dengan memasukkan nomor acak baru dari rentang yang lebih besar dengan setiap loop berturut-turut. Jika sudah ada angka yang sama atau lebih tinggi dari itu, pindahkan angka-angka acak ke atas sehingga mereka mentransfer ke kisaran indeks acak baru yang lebih besar.
sumber
Hal lain: Anda bisa menggunakan refleksi. Jika Anda akan menembolok ini dengan benar, maka itu akan mengklon 1.000.000 objek dalam 5,6 detik (sayangnya, 16,4 detik dengan objek dalam).
Saya mengukurnya dengan cara yang sederhana, dengan menggunakan kelas Watcher.
HASIL: Dengan objek dalam PersonInstance - 16.4, PersonInstance = null - 5.6
CopyFactory hanyalah kelas pengujian saya di mana saya memiliki selusin tes termasuk penggunaan ekspresi. Anda bisa menerapkan ini dalam bentuk lain dalam ekstensi atau apa pun. Jangan lupa tentang caching.
Saya belum menguji serialisasi, tapi saya ragu dengan peningkatan dengan sejuta kelas. Saya akan mencoba sesuatu protobuf cepat / newton.
PS: Demi membaca kesederhanaan, saya hanya menggunakan properti otomatis di sini. Saya dapat memperbarui dengan FieldInfo, atau Anda harus dengan mudah mengimplementasikannya sendiri.
Saya baru-baru ini menguji serializer Protokol Buffer dengan fungsi DeepClone di luar kotak. Ia menang dengan 4,2 detik pada sejuta objek sederhana, tetapi ketika sampai pada objek dalam, ia menang dengan hasil 7,4 detik.
RINGKASAN: Jika Anda tidak memiliki akses ke kelas, maka ini akan membantu. Kalau tidak, itu tergantung pada jumlah objek. Saya pikir Anda bisa menggunakan refleksi hingga 10.000 objek (mungkin sedikit kurang), tetapi untuk lebih dari ini serializer Protokol Buffer akan tampil lebih baik.
sumber
Ada cara sederhana untuk mengkloning objek di C # menggunakan serializer dan deserializer JSON.
Anda dapat membuat kelas ekstensi:
Untuk mengkloning dan objek:
sumber