How do I clone a generic list in C#?

前端 未结 26 2383
失恋的感觉
失恋的感觉 2020-11-22 01:27

I have a generic list of objects in C#, and wish to clone the list. The items within the list are cloneable, but there doesn\'t seem to be an option to do list.Clone()

相关标签:
26条回答
  • 2020-11-22 02:05
        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;
            }
        }
    
    0 讨论(0)
  • 2020-11-22 02:06

    You can use an extension method.

    static class Extensions
    {
        public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
        {
            return listToClone.Select(item => (T)item.Clone()).ToList();
        }
    }
    
    0 讨论(0)
  • 2020-11-22 02:08

    I'll be lucky if anybody ever reads this... but in order to not return a list of type object in my Clone methods, I created an interface:

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

    Then I specified the extension:

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

    And here is an implementation of the interface in my A/V marking software. I wanted to have my Clone() method return a list of VidMark (while the ICloneable interface wanted my method to return a list of object):

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

    And finally, the usage of the extension inside a class:

    private List<VidMark> _VidMarks;
    private List<VidMark> _UndoVidMarks;
    
    //Other methods instantiate and fill the lists
    
    private void SetUndoVidMarks()
    {
        _UndoVidMarks = _VidMarks.Clone();
    }
    

    Anybody like it? Any improvements?

    0 讨论(0)
  • 2020-11-22 02:08

    My friend Gregor Martinovic and I came up with this easy solution using a JavaScript Serializer. There is no need to flag classes as Serializable and in our tests using the Newtonsoft JsonSerializer even faster than using BinaryFormatter. With extension methods usable on every object.

    Standard .NET JavascriptSerializer option:

    public static T DeepCopy<T>(this T value)
    {
        JavaScriptSerializer js = new JavaScriptSerializer();
    
        string json = js.Serialize(value);
    
        return js.Deserialize<T>(json);
    }
    

    Faster option using Newtonsoft JSON:

    public static T DeepCopy<T>(this T value)
    {
        string json = JsonConvert.SerializeObject(value);
    
        return JsonConvert.DeserializeObject<T>(json);
    }
    
    0 讨论(0)
  • 2020-11-22 02:08

    Using a cast may be helpful, in this case, for a shallow copy:

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

    applied to generic list:

    List<T> Clone<T>(List<T> argument) => (List<T>)CloneList(argument);
    
    0 讨论(0)
  • 2020-11-22 02:08

    For a deep copy, ICloneable is the correct solution, but here's a similar approach to ICloneable using the constructor instead of the ICloneable interface.

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

    you'll need the following library where you make the copy

    using System.Linq
    

    you could also use a for loop instead of System.Linq, but Linq makes it concise and clean. Likewise you could do as other answers have suggested and make extension methods, etc., but none of that is necessary.

    0 讨论(0)
提交回复
热议问题