Nasıl C # genel bir listesini klonlayabilirim?


592

C # nesnelerin genel bir listesi var ve listeyi klonlamak istiyorum. Listedeki öğeler klonlanabilir, ancak bir seçenek yok gibi görünüyor list.Clone().

Bunun kolay bir yolu var mı?


44
Derin bir kopya mı yoksa sığ bir kopya mı arıyorsun
orip

10
Derin ve sığ kopyalar nelerdir?
Albay Panik


3
@orip clone()Tanım olarak derin bir kopya değil mi? C # ile kolayca işaretçiler geçebilirsiniz =, diye düşündüm.
Chris

13
@ Sığ bir kopya işaretçi kopya bir seviye daha derin kopyalar. Örneğin, bir listenin sığ bir kopyası aynı öğelere sahip olacaktır, ancak farklı bir liste olacaktır.
OriP

Yanıtlar:


385

Bir uzantı yöntemi kullanabilirsiniz.

static class Extensions
{
    public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
    {
        return listToClone.Select(item => (T)item.Clone()).ToList();
    }
}

71
Listenin tüm dizisini her zaman yeniden boyutlandırmak zorunda kalmadan listeye önceden ayırabildiğinden, List.ConvertAll'ın daha hızlı yapabileceğini düşünüyorum.
MichaelGG

2
@MichaelGG, Dönüştürmek istemiyorsanız, ancak listedeki öğeleri Klonla / Çoğalt'ı seçerseniz? Bu işe yarar mı? || var clonedList = ListOfStrings.ConvertAll (p => p);
IbrarMumtaz

29
@IbrarMumtaz: Bu var clonedList = new List <string> (ListOfStrings) ile aynıdır;
Brandon Arnold

4
Güzel çözüm! Bu arada genel statik Listeyi tercih ediyorum <T> CLone <T> ... Bu gibi durumlarda daha kullanışlıdır, çünkü daha fazla oyuncuya gerek yoktur: List <MyType> cloned = listToClone.Clone ();
Plutoz

2
Bu derin klonlama
George Birbilis

512

Öğeleriniz değer türüyse, şunları yapabilirsiniz:

List<YourType> newList = new List<YourType>(oldList);

Ancak, bunlar referans türleri ise ve derin bir kopya istiyorsanız (öğelerinizin düzgün bir şekilde uygulandığını varsayarak ICloneable), şöyle bir şey yapabilirsiniz:

List<ICloneable> oldList = new List<ICloneable>();
List<ICloneable> newList = new List<ICloneable>(oldList.Count);

oldList.ForEach((item) =>
    {
        newList.Add((ICloneable)item.Clone());
    });

Açıkçası, ICloneableyukarıdaki jenerikleri değiştirin ve uyguladığınız eleman türünüzle yapın ICloneable.

Öğe türünüz desteklemiyor ICloneableancak bir kopya oluşturucuya sahipse, bunun yerine bunu yapabilirsiniz:

List<YourType> oldList = new List<YourType>();
List<YourType> newList = new List<YourType>(oldList.Count);

oldList.ForEach((item)=>
    {
        newList.Add(new YourType(item));
    });

Şahsen, ICloneabletüm üyelerin derin bir kopyasını garanti etme ihtiyacı nedeniyle kaçınırım . Bunun yerine, kopya oluşturucuyu veya bunun gibi bir fabrika yöntemini YourType.CopyFrom(YourType itemToCopy)yeni bir örneğini döndürmesini öneririm YourType.

Bu seçeneklerden herhangi biri bir yöntemle (uzantı veya başka bir şekilde) sarılabilir.


1
List <T> .ConvertAll yeni bir liste oluşturmak ve bir foreach + add yapmaktan daha hoş görünebilir düşünüyorum.
MichaelGG

2
@Dimitri: Hayır, bu doğru değil. Sorun, ICloneabletanımlandığında, tanım asla klonun derin mi yoksa sığ mı olduğunu belirtmedi, bu nedenle bir nesne uyguladığında hangi tür Klonlama işleminin yapılacağını belirleyemezsiniz. Bu, derin bir klon yapmak List<T>istiyorsanız, ICloneablederin bir kopya olduğundan emin olmak zorunda kalmadan yapmanız gerektiği anlamına gelir .
Jeff Yates

5
Neden AddRange yöntemini kullanmıyorsunuz? ( newList.AddRange(oldList.Select(i => i.Clone())veya newList.AddRange(oldList.Select(i => new YourType(i))
phoog

5
@phoog: Kodu tararken biraz daha az okunabilir / anlaşılabilir olduğunu düşünüyorum, hepsi bu. Okunabilirlik benim için kazanıyor.
Jeff Yates

1
@JeffYates: Yeterince düşünülmeyen bir kırışıklık, şeylerin genellikle sadece onları mutasyona uğratacak bir yürütme yolu varsa kopyalanması gerektiğidir. Bu var çok değişmez tipleri değişken türde bir örneği başvurusu tutun varsa, ancak o dönüşecek şey bu örneği maruz asla ortak. Hiç değişmeyecek şeylerin gereksiz kopyalanması bazen önemli bir performans kaybı olabilir ve bellek kullanımını büyüklük derecelerine göre artırabilir.
supercat

84

Sığ bir kopya için, bunun yerine genel List sınıfının GetRange yöntemini kullanabilirsiniz.

List<int> oldList = new List<int>( );
// Populate oldList...

List<int> newList = oldList.GetRange(0, oldList.Count);

Alıntı sahibi: Generics Recipes


43
Bunu, kopyalanacak bir Liste <T> belirtmek için List <T> yapıcısını kullanarak da başarabilirsiniz. örneğin var shallowClonedList = new List <MyObject> (originalList);
Arkiliknam

9
Sık kullanırım List<int> newList = oldList.ToList(). Aynı etki. Ancak Arkiliknam'ın çözümü bence okunabilirlik açısından en iyisi.
Dan Bechard

82
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;
}

Bu, C # ve .NET 2.0 ile yapmanın bir yoludur. Nesneniz olması gerekiyor [Serializable()]. Amaç, tüm referansları kaybetmek ve yenilerini oluşturmaktır.


11
+1 - bu cevabı beğendim - hızlı, kirli, kötü ve çok etkilidir. Silverlight'ta kullandım ve BinarySerializer kullanılamadığı için DataContractSerializer'ı kullandım. Bunu yapabildiğinizde kimlerin nesne kopyalama kodu yazması gerekir? :)
slugster

3
Bunu severim. "Doğru" bir şeyler yapmak güzel olsa da, hızlı ve kirli çoğu zaman kullanışlı olur.
Odrade

3
Hızlı! ama: Neden kirli?
raiserle

2
Bu derin klonlar ve hızlı ve kolaydır. Bu sayfadaki diğer önerilere dikkat et. Birkaç tane denedim ve derin klonlamıyorlar.
RandallTo

2
Sadece olumsuz yönü, eğer bunu diyebilirseniz, bunun çalışması için sınıflarınızın Seri olarak işaretlenmelidir.
Tuukka Haapaniemi

29

Bir listeyi klonlamak için .ToList () öğesini çağırmanız yeterlidir. Bu sığ bir kopya oluşturur.

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 }
> 

3
Şimdiye kadarki en basit çözüm
curveorzos

28
Küçük bir uyarı, bu sığ bir kopyadır ... Bu, iki liste nesnesi oluşturur, ancak içindeki nesneler aynı olacaktır. Bir özelliği değiştirmek, orijinal listedeki aynı nesneyi / özelliği değiştirir.
Mark G

22

Hafif bir değişiklikten sonra da klonlayabilirsiniz:

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;
}

T serileştirilebilir olmalıdır, aksi takdirde System.Runtime.Serialization.SerializationException alırsınız.
Bence Végert

İyi cevap. Bir ipucu: İstisnayıif (!obj.GetType().IsSerializable) return default(T); önleyen ilk ifade olarak ekleyebilirsiniz . Ve bunu bir uzantı yöntemiyle değiştirirseniz, Elvis operatörünü var b = a?.DeepClone();( var a = new List<string>() { "a", "b" }; örneğin verilen gibi) bile kullanabilirsiniz .
Matt

15

İçinizdeki her bir nesnenin gerçek bir klonuna ihtiyacınız olmadığı sürece List<T>, bir listeyi klonlamanın en iyi yolu eski parametre ile toplama parametresi olarak yeni bir liste oluşturmaktır.

List<T> myList = ...;
List<T> cloneOfMyList = new List<T>(myList);

Ekleme myListveya çıkarma gibi değişiklikler etkilemezcloneOfMyList veya tam tersi.

Ancak iki Listenin içerdiği gerçek nesneler hala aynıdır.


Kabul ediyorum user49126, bunun sığ bir kopya olduğunu ve bir listede yapılan değişikliklerin diğer listeye yansıtıldığını görüyorum.
Seidleroni

1
@Seidleroni, yanılıyorsun. Listede yapılan değişiklikler diğer listeden etkilenir, listenin kendisinde değişiklik yapılmaz.
Wellington Zanelli

Bu sığ bir kopya.
Elliot Chen

Bu nasıl sığ bir kopya?
mko

2
@WellingtonZanelli Bir öğeyi myList'ten kaldırmanın, onu cloneOfMyList'ten de kaldırdığını doğruladı.
Nick Gallimore

13

Klonlamak için AutoMapper'ı (veya tercih ettiğiniz herhangi bir haritalama lib'ini) basit ve çok bakım yapılabilir.

Eşlemenizi tanımlayın:

Mapper.CreateMap<YourType, YourType>();

Sihri yapın:

YourTypeList.ConvertAll(Mapper.Map<YourType, YourType>);

13

Yalnızca değer türlerini önemsiyorsanız ...

Ve türünü biliyorsunuz:

List<int> newList = new List<int>(oldList);

Daha önce türü bilmiyorsanız, bir yardımcı fonksiyona ihtiyacınız olacak:

List<T> Clone<T>(IEnumerable<T> oldList)
{
    return newList = new List<T>(oldList);
}

Sadece:

List<string> myNewList = Clone(myOldList);

15
Bu unsurları klonlamaz.
Jeff Yates

10

Projenizde zaten Newtonsoft.Json'a başvurduysanız ve nesneleriniz serileştirilebilirse, her zaman kullanabilirsiniz:

List<T> newList = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(listToCopy))

Muhtemelen bunu yapmanın en etkili yolu değil, ancak 1000'lerin 100'ünü yapmazsanız, hız farkını bile fark etmeyebilirsiniz.


4
Bu hız farkı değil, okunabilirlikle ilgili. Bu kod satırına gelirsem kafamı tokatlar ve neden üçüncü bir kütüphane tanıttılar ve niçin olduğunu bilmiyordum ki bir nesneyi serileştirip serileştirmeyi merak ediyorlardı. Ayrıca, dairesel bir yapıya sahip nesnelerin bulunduğu bir model listesi için bu işe yaramaz.
Jonathon Cwik

1
Bu kod benim için derin klonlama için mükemmel çalıştı. Uygulamaya Dev için Prod için belge boilerplate geçiriyor. Her nesne birkaç belge şablonu nesnesinin bir paketidir ve sırayla her belge bir paragraf nesneleri listesinden oluşur. Bu kod, .NET "kaynak" nesnelerini serileştirmeme ve yeni "hedef" nesnelere derhal serileştirmeme izin veriyor, bu da daha sonra farklı bir ortamda bir SQL veritabanına kaydediliyor. Tonlarca araştırmadan sonra, çoğu fazla hantal olan birçok şey buldum ve bunu denemeye karar verdim. Bu kısa ve esnek yaklaşım "doğru" idi!
Developer63

3
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;
}

3
public class CloneableList<T> : List<T>, ICloneable where T : ICloneable
{
  public object Clone()
  {
    var clone = new List<T>();
    ForEach(item => clone.Add((T)item.Clone()));
    return clone;
  }
}

3
    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;
        }
    }

3

Arkadaşım Gregor Martinovic ve ben bir JavaScript Serializer kullanarak bu kolay çözümü bulduk. Sınıfları Serializable olarak ve Newtonsoft JsonSerializer'ı kullanan testlerimizde BinaryFormatter kullanmaktan daha hızlı bir şekilde işaretlemeye gerek yoktur. Her nesnede kullanılabilen uzatma yöntemleri ile.

Standart .NET JavascriptSerializer seçeneği:

public static T DeepCopy<T>(this T value)
{
    JavaScriptSerializer js = new JavaScriptSerializer();

    string json = js.Serialize(value);

    return js.Deserialize<T>(json);
}

Newtonsoft JSON kullanarak daha hızlı seçenek :

public static T DeepCopy<T>(this T value)
{
    string json = JsonConvert.SerializeObject(value);

    return JsonConvert.DeserializeObject<T>(json);
}

2
Özel üyeler JSON yöntemi kullanılarak klonlanmaz. stackoverflow.com/a/78612/885627
himanshupareek66

3
 //try this
 List<string> ListCopy= new List<string>(OldList);
 //or try
 List<T> ListCopy=OldList.ToList();

3

Kimse bunu okursa şanslı olurum ... ama Clone yöntemlerimde bir tür nesne listesi döndürmemek için bir arayüz oluşturdum:

public interface IMyCloneable<T>
{
    T Clone();
}

Sonra uzantıyı belirttim:

public static List<T> Clone<T>(this List<T> listToClone) where T : IMyCloneable<T>
{
    return listToClone.Select(item => (T)item.Clone()).ToList();
}

Ve işte A / V markalama yazılımımdaki arayüzün bir uygulaması. Clone () yöntemimin VidMark listesini döndürmesini istedim (ICloneable arayüzü yöntemimin nesne listesini döndürmesini istediğinde):

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();
    }
}

Ve son olarak, bir sınıf içinde uzantının kullanımı:

private List<VidMark> _VidMarks;
private List<VidMark> _UndoVidMarks;

//Other methods instantiate and fill the lists

private void SetUndoVidMarks()
{
    _UndoVidMarks = _VidMarks.Clone();
}

Bunu beğenen var mı? Herhangi bir gelişme var mı?


2

Ayrıca listeyi kullanarak bir diziye dönüştürebilir ToArrayve ardından diziyi klonlayabilirsiniz Array.Clone(...). Gereksinimlerinize bağlı olarak, Array sınıfında yer alan yöntemler ihtiyaçlarınızı karşılayabilir.


Bu çalışmıyor; klonlanmış STILL dizisindeki değerlerde yapılan değişiklikler orijinal listedeki değerleri değiştirir.
Bernoulli Lizard

var clonedList = ListOfStrings.ConvertAll (p => p) kullanabilirsiniz; @IbrarMumtaz tarafından verildiği gibi .... Etkili çalışır ... Bir listedeki değişiklikler kendi içinde tutulur ve başka bir başkasına yansıtmaz
zainul

2

Uzantı yöntemini kullanabilirsiniz:

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;
        }
   };

}

Örneğin, değer türü üyelerini kullanarak tüm nesneleri klonlayabilirsiniz, bu sınıfı göz önünde bulundurun:

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 
    }
};

Not: kopyada (veya klonda) herhangi bir değişiklik yaparsanız, orijinal nesne etkilenmez.


2

Aynı kapasiteye sahip klonlanmış bir listeye ihtiyacınız varsa, bunu deneyebilirsiniz:

public static List<T> Clone<T>(this List<T> oldList)
{
    var newList = new List<T>(oldList.Capacity);
    newList.AddRange(oldList);
    return newList;
}

1

IClonable'ı uygulamayan öğelerin ICollection'ını dönüştüren kendi uzantısı için yaptım

static class CollectionExtensions
{
    public static ICollection<T> Clone<T>(this ICollection<T> listToClone)
    {
        var array = new T[listToClone.Count];
        listToClone.CopyTo(array,0);
        return array.ToList();
    }
}

bazı koleksiyonlar (ör. Silverlight'taki DataGrid'in SelectedItems'i), bu yaklaşımla ilgili bir sorun olan CopyTo uygulamasını
atlıyor


1

Bu durumda, sığ bir kopya için alçı kullanmak yardımcı olabilir:

IList CloneList(IList list)
{
    IList result;
    result = (IList)Activator.CreateInstance(list.GetType());
    foreach (object item in list) result.Add(item);
    return result;
}

genel listeye uygulandı:

List<T> Clone<T>(List<T> argument) => (List<T>)CloneList(argument);

1

Derin bir kopya için, ICloneable doğru çözümdür, ancak burada ICloneable arabirimi yerine yapıcı kullanılarak ICloneable için benzer bir yaklaşım vardır.

public class Student
{
  public Student(Student student)
  {
    FirstName = student.FirstName;
    LastName = student.LastName;
  }

  public string FirstName { get; set; }
  public string LastName { get; set; }
}

// wherever you have the list
List<Student> students;

// and then where you want to make a copy
List<Student> copy = students.Select(s => new Student(s)).ToList();

kopyayı yaptığınız aşağıdaki kütüphaneye ihtiyacınız olacak

using System.Linq

System.Linq yerine bir for döngüsü de kullanabilirsiniz, ancak Linq bunu özlü ve temiz yapar. Benzer şekilde, diğer cevapların önerdiği gibi yapabilir ve uzatma yöntemleri vb. Yapabilirsiniz, ancak bunların hiçbiri gerekli değildir.


Buna "kopya oluşturucu" denir. Bu, hataya açık bir yaklaşımdır, Öğrenci'ye her yeni alan eklediğinizde, bunu kopya oluşturucuya eklemeyi hatırlamanız gerekir. "Klon" un arkasındaki ana fikir bu problemden kaçınmaktır.
kenno

2
ICloneable ile bile, sınıfınızda bir "Klon" yöntemine sahip olmanız gerekir. Yansımayı kullanmadığınız sürece (yukarıdaki yaklaşımda da kullanabilirsiniz), bu Clone yöntemi yukarıdaki kopya oluşturucu yaklaşımına çok benzeyecek ve yeni / değiştirilmiş alanlar için güncelleme yapma sorunu yaşayacaksınız. Ancak "Sınıfın alanları değiştiğinde sınıf güncellenmelidir" der. Tabii ki;)
ztorstri

0

Aşağıdaki kod, minimum değişiklik içeren bir listeye aktarılmalıdır.

Temelde, her ardışık döngü ile daha geniş bir aralıktan yeni bir rastgele sayı ekleyerek çalışır. Zaten aynı veya ondan daha yüksek olan sayılar varsa, bu rastgele sayıları bir yukarı kaydırın, böylece yeni daha büyük rastgele dizin aralığına aktarın.

// Example Usage
int[] indexes = getRandomUniqueIndexArray(selectFrom.Length, toSet.Length);

for(int i = 0; i < toSet.Length; i++)
    toSet[i] = selectFrom[indexes[i]];


private int[] getRandomUniqueIndexArray(int length, int count)
{
    if(count > length || count < 1 || length < 1)
        return new int[0];

    int[] toReturn = new int[count];
    if(count == length)
    {
        for(int i = 0; i < toReturn.Length; i++) toReturn[i] = i;
        return toReturn;
    }

    Random r = new Random();
    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;
}

0

Başka bir şey: yansıma kullanabilirsiniz. Bunu düzgün bir şekilde önbelleğe alırsanız, 5.000 saniyede 1.000.000 nesneyi (ne yazık ki iç nesnelerle 16.4 saniye) klonlar.

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Person
{
       ...
      Job JobDescription
       ...
}

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Job
{...
}

private static readonly Type stringType = typeof (string);

public static class CopyFactory
{
    static readonly Dictionary<Type, PropertyInfo[]> ProperyList = new Dictionary<Type, PropertyInfo[]>();

    private static readonly MethodInfo CreateCopyReflectionMethod;

    static CopyFactory()
    {
        CreateCopyReflectionMethod = typeof(CopyFactory).GetMethod("CreateCopyReflection", BindingFlags.Static | BindingFlags.Public);
    }

    public static 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)
        {
            var value = prop.GetValue(source, null);
            prop.SetValue(copyInstance,
                value != null && prop.PropertyType.IsClass && prop.PropertyType != stringType ? CreateCopyReflectionMethod.MakeGenericMethod(prop.PropertyType).Invoke(null, new object[] { value }) : value, null);
        }

        return copyInstance;
    }

Watcher sınıfını kullanarak basit bir şekilde ölçtüm.

 var person = new Person
 {
     ...
 };

 for (var i = 0; i < 1000000; i++)
 {
    personList.Add(person);
 }
 var watcher = new Stopwatch();
 watcher.Start();
 var copylist = personList.Select(CopyFactory.CreateCopyReflection).ToList();
 watcher.Stop();
 var elapsed = watcher.Elapsed;

SONUÇ: PersonInstance - 16.4 iç nesnesi ile PersonInstance = null - 5.6

CopyFactory, ifade kullanımı da dahil olmak üzere onlarca testimin olduğu test sınıfım. Bunu başka bir biçimde bir uzantıda ya da her neyse uygulayabilirsiniz. Önbelleğe almayı unutmayın.

Serileştirmeyi henüz test etmedim, ancak bir milyon sınıfla yapılan bir iyileşmeden şüphe ediyorum. Hızlı bir şekilde protobuf / newton deneyeceğim.

PS: basitlik okumak amacıyla, ben sadece burada otomatik mülkiyet kullandım. FieldInfo ile güncelleyebilirim, ya da bunu kendi başınıza kolayca uygulamanız gerekir.

Son zamanlarda DeepClone fonksiyonu ile Protokol Tamponları serileştiricisini test ettim . Bir milyon basit nesnede 4.2 saniye kazanır, ancak iç nesneler söz konusu olduğunda, 7.4 saniye ile kazanır.

Serializer.DeepClone(personList);

Hepsini kapa Özet: Sınıflara erişiminiz yoksa, bu yardımcı olacaktır. Aksi takdirde, nesnelerin sayısına bağlıdır. Sanırım 10.000 nesneye kadar yansımayı kullanabilirsiniz (belki biraz daha az), ancak bundan daha fazlası için Protokol Tamponları serileştirici daha iyi performans gösterecektir.


0

Bir JSON serileştirici ve serisini kaldırıcı kullanarak C # içindeki nesneleri klonlamanın basit bir yolu vardır.

Bir uzantı sınıfı oluşturabilirsiniz:

using Newtonsoft.Json;

static class typeExtensions
{
    [Extension()]
    public static T jsonCloneObject<T>(T source)
    {
    string json = JsonConvert.SerializeObject(source);
    return JsonConvert.DeserializeObject<T>(json);
    }
}

Klonlamak ve itiraz etmek için:

obj clonedObj = originalObj.jsonCloneObject;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.