Saya memiliki daftar generik objek di C#, dan berharap untuk mengkloning daftar. Item dalam daftar yang cloneable, tapi ada doesn't tampaknya menjadi pilihan untuk melakukan daftar.Clone()
.
Apakah ada cara mudah ini?
Jika unsur-unsur nilai jenis, maka anda hanya dapat melakukan:
List<YourType> newList = new List<YourType>(oldList);
Namun, jika mereka adalah jenis referensi dan anda ingin dalam salinan (dengan asumsi anda benar menerapkan unsur-unsur ICloneable
), anda bisa melakukan sesuatu seperti ini:
List<ICloneable> oldList = new List<ICloneable>();
List<ICloneable> newList = new List<ICloneable>(oldList.Count);
oldList.ForEach((item) =>
{
newList.Add((ICloneable)item.Clone());
});
Jelas, ganti ICloneable
di atas obat generik dan cor dengan apa elemen anda adalah tipe yang menerapkan ICloneable
.
Jika anda jenis elemen doesn't dukungan ICloneable
tetapi tidak memiliki copy constructor, anda bisa melakukan hal ini sebagai gantinya:
List<YourType> oldList = new List<YourType>();
List<YourType> newList = new List<YourType>(oldList.Count);
oldList.ForEach((item)=>
{
newList.Add(new YourType(item));
});
Secara pribadi, saya akan menghindari ICloneable
karena kebutuhan untuk menjamin dalam salinan dari semua anggota. Sebaliknya, saya'd sarankan copy-konstruktor atau metode pabrik seperti YourType.CopyFrom(YourType itemToCopy)
yang mengembalikan sebuah instance baru dari YourType
.
Setiap pilihan ini bisa dibungkus dengan metode (ekstensi atau sebaliknya).
Untuk salinan dangkal, anda dapat menggunakan GetRange metode generik Daftar kelas.
List<int> oldList = new List<int>( );
// Populate oldList...
List<int> newList = oldList.GetRange(0, oldList.Count);
Dikutip dari: Resep obat Generik
public static object DeepClone(object obj)
{
object objResult = null;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
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 membutuhkan untuk menjadi [Serializable()]
. Tujuannya adalah untuk menurunkan semua referensi dan membangun yang baru.
Setelah sedikit modifikasi, anda juga bisa clone:
public static T DeepClone<T>(T obj)
{
T objResult;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, obj);
ms.Position = 0;
objResult = (T)bf.Deserialize(ms);
}
return objResult;
}
Untuk mengkloning daftar panggil .Kedaftar()
Microsoft (R) Roslyn C# Compiler version 2.3.2.62116
Loading context from 'CSharpInteractive.rsp'.
Type "#help" for more information.
> var x = new List<int>() { 3, 4 };
> var y = x.ToList();
> x.Add(5)
> x
List<int>(3) { 3, 4, 5 }
> y
List<int>(2) { 3, 4 }
>
Kecuali anda butuhkan sebenarnya clone dari setiap objek di dalam Daftar<T>
, cara terbaik untuk mengkloning daftar untuk membuat daftar baru dengan yang lama daftar sebagai koleksi parameter.
List<T> myList = ...;
List<T> cloneOfMyList = new List<T>(myList);
Perubahan myList
seperti menyisipkan atau menghapus tidak akan mempengaruhi cloneOfMyList
dan sebaliknya.
Benda-benda yang sebenarnya dua Daftar yang berisi yang masih sama namun.
Jika anda hanya peduli tentang nilai jenis...
Dan anda tahu jenis:
List<int> newList = new List<int>(oldList);
Jika anda don't tahu jenis sebelumnya, anda'll membutuhkan fungsi pembantu:
List<T> Clone<T>(IEnumerable<T> oldList)
{
return newList = new List<T>(oldList);
}
Hanya:
List<string> myNewList = Clone(myOldList);
Gunakan AutoMapper (atau apapun pemetaan lib anda sukai) untuk mengkloning sederhana dan banyak dipelihara.
Menentukan pemetaan:
Mapper.CreateMap<YourType, YourType>();
Melakukan sihir:
YourTypeList.ConvertAll(Mapper.Map<YourType, YourType>);
Jika anda sudah dirujuk Newtonsoft.Json dalam proyek anda dan benda-benda yang serializeable anda selalu bisa menggunakan:
List<T> newList = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(listToCopy))
Mungkin bukan cara yang paling efisien untuk melakukannya, tetapi jika anda're melakukannya 100 1000s kali anda mungkin bahkan tidak menyadari perbedaan kecepatan.
public List<TEntity> Clone<TEntity>(List<TEntity> o1List) where TEntity : class , new()
{
List<TEntity> retList = new List<TEntity>();
try
{
Type sourceType = typeof(TEntity);
foreach(var o1 in o1List)
{
TEntity o2 = new TEntity();
foreach (PropertyInfo propInfo in (sourceType.GetProperties()))
{
var val = propInfo.GetValue(o1, null);
propInfo.SetValue(o2, val);
}
retList.Add(o2);
}
return retList;
}
catch
{
return retList;
}
}
public static Object CloneType(Object objtype)
{
Object lstfinal = new Object();
using (MemoryStream memStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
binaryFormatter.Serialize(memStream, objtype); memStream.Seek(0, SeekOrigin.Begin);
lstfinal = binaryFormatter.Deserialize(memStream);
}
return lstfinal;
}
I'akan beruntung jika ada yang pernah membaca ini... tapi dalam rangka untuk tidak kembali daftar tipe objek di Clone metode, aku menciptakan sebuah antarmuka:
public interface IMyCloneable<T>
{
T Clone();
}
Kemudian saya ditentukan ekstensi:
public static List<T> Clone<T>(this List<T> listToClone) where T : IMyCloneable<T>
{
return listToClone.Select(item => (T)item.Clone()).ToList();
}
Dan berikut ini adalah implementasi antarmuka pada saya A/V menandai perangkat lunak. Saya ingin memiliki saya Clone() metode kembali daftar VidMark (sementara ICloneable antarmuka yang ingin saya metode untuk mengembalikan daftar objek):
public class VidMark : IMyCloneable<VidMark>
{
public long Beg { get; set; }
public long End { get; set; }
public string Desc { get; set; }
public int Rank { get; set; } = 0;
public VidMark Clone()
{
return (VidMark)this.MemberwiseClone();
}
}
Dan akhirnya, penggunaan ekstensi di dalam kelas:
private List<VidMark> _VidMarks;
private List<VidMark> _UndoVidMarks;
//Other methods instantiate and fill the lists
private void SetUndoVidMarks()
{
_UndoVidMarks = _VidMarks.Clone();
}
Orang seperti itu? Perbaikan?
Anda dapat menggunakan metode penyuluhan:
namespace extension
{
public class ext
{
public static List<double> clone(this List<double> t)
{
List<double> kop = new List<double>();
int x;
for (x = 0; x < t.Count; x++)
{
kop.Add(t[x]);
}
return kop;
}
};
}
Anda dapat mengkloning semua benda dengan menggunakan nilai mereka jenis anggota misalnya, menganggap kelas ini:
public class matrix
{
public List<List<double>> mat;
public int 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 so
int 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 cloned
return copy; // and copy of original is returned
}
};
Catatan: jika anda melakukan perubahan apapun di copy (atau tiruan) itu tidak akan mempengaruhi objek asli.
Jika anda membutuhkan kloning daftar dengan kapasitas yang sama, anda dapat mencoba ini:
public static List<T> Clone<T>(this List<T> oldList)
{
var newList = new List<T>(oldList.Capacity);
newList.AddRange(oldList);
return newList;
}
Teman saya Gregor Martinovic dan saya datang dengan ini solusi mudah menggunakan JavaScript Serializer. Ada tidak perlu untuk menandai kelas sebagai Serializable dan dalam pengujian kami menggunakan Newtonsoft JsonSerializer bahkan lebih cepat daripada menggunakan BinaryFormatter. Dengan metode ekstensi yang dapat digunakan pada setiap objek.
Standar .NET JavascriptSerializer pilihan:
public static T DeepCopy<T>(this T value)
{
JavaScriptSerializer js = new JavaScriptSerializer();
string json = js.Serialize(value);
return js.Deserialize<T>(json);
}
Lebih cepat menggunakan opsi Newtonsoft JSON:
public static T DeepCopy<T>(this T value)
{
string json = JsonConvert.SerializeObject(value);
return JsonConvert.DeserializeObject<T>(json);
}