Deep Copy of a C# Object

后端 未结 4 726
梦毁少年i
梦毁少年i 2020-12-17 00:44

I am working on some code that is written in C#. In this app, I have a custom collection defined as follows:

public class ResultList : IEnumerable&l         


        
相关标签:
4条回答
  • 2020-12-17 01:00

    Here is something that I needed and wrote, it uses reflection to copy every property (and private ones if specified)

    public static class ObjectCloner
    {
        public static T Clone<T>(object obj, bool deep = false) where T : new()
        {
            if (!(obj is T))
            {
                throw new Exception("Cloning object must match output type");
            }
    
            return (T)Clone(obj, deep);
        }
    
        public static object Clone(object obj, bool deep)
        {
            if (obj == null)
            {
                return null;
            }
    
            Type objType = obj.GetType();
    
            if (objType.IsPrimitive || objType == typeof(string) || objType.GetConstructors().FirstOrDefault(x => x.GetParameters().Length == 0) == null)
            {
                return obj;
            }
    
            List<PropertyInfo> properties = objType.GetProperties().ToList();
            if (deep)
            {
                properties.AddRange(objType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic)); 
            }
    
            object newObj = Activator.CreateInstance(objType);
    
            foreach (var prop in properties)
            {
                if (prop.GetSetMethod() != null)
                {
                    object propValue = prop.GetValue(obj, null);
                    object clone = Clone(propValue, deep);
                    prop.SetValue(newObj, clone, null);
                }
            }
    
            return newObj;
        }
    }
    
    0 讨论(0)
  • 2020-12-17 01:05

    The approach involving the least coding effort is that of serializing and deserializing through a BinaryFormatter.

    You could define the following extension method (taken from Kilhoffer’s answer):

    public static T DeepClone<T>(T obj)
    {
        using (var ms = new MemoryStream())
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(ms, obj);
            ms.Position = 0;
            return (T)formatter.Deserialize(ms);
        }
    }
    

    …and then just call:

    ResultList<T> clone = DeepClone(original);
    
    0 讨论(0)
  • 2020-12-17 01:09

    Expanding on @Georgi-it, I had to modify his code to handle properties whose type inherits List:

    public static class ObjectCloner {
        public static T Clone<T>(object obj, bool deep = false) where T : new() {
            if (!(obj is T)) {
                throw new Exception("Cloning object must match output type");
            }
    
            return (T)Clone(obj, deep);
        }
    
        public static object Clone(object obj, bool deep) {
            if (obj == null) {
                return null;
            }
    
            Type objType = obj.GetType();
    
            if (objType.IsPrimitive || objType == typeof(string) || objType.GetConstructors().FirstOrDefault(x => x.GetParameters().Length == 0) == null) {
                return obj;
            }
    
            List<PropertyInfo> properties = objType.GetProperties().ToList();
            if (deep) {
                properties.AddRange(objType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic));
            }
    
            object newObj = Activator.CreateInstance(objType);
    
            foreach (var prop in properties) {
                if (prop.GetSetMethod() != null) {
                    var proceed = true;
                    if (obj is IList) {
                        var listType = obj.GetType().GetProperty("Item").PropertyType;
                        if (prop.PropertyType == listType) {
                            proceed = false;
                            foreach (var item in obj as IList) {
                                object clone = Clone(item, deep);
                                (newObj as IList).Add(clone);                               
                            }                           
                        }                       
                    }
    
                    if (proceed) {
                        object propValue = prop.GetValue(obj, null);
                        object clone = Clone(propValue, deep);
                        prop.SetValue(newObj, clone, null);
                    }                   
                }
            }
    
            return newObj;
        }
    }
    
    0 讨论(0)
  • 2020-12-17 01:12

    One of the reasons why your ResultList class won't work with Jon Skeet's example is because it does not implement the ICloneable interface.

    Implement ICloneable on all the classes that you need cloned, e.g.

    public class ResultItem : ICloneable
    {
      public object Clone()
      {
        var item = new ResultItem
                     {
                       ID = ID,
                       Name = Name,
                       isLegit = isLegit
                     };
        return item;
      }
    }
    

    And also on ResultList:

    public class ResultList<T> : IEnumerable<T>, ICloneable where T : ICloneable
    {
      public List<T> Results { get; set; }
      public decimal CenterLatitude { get; set; }
      public decimal CenterLongitude { get; set; }
    
      public object Clone()
      {
        var list = new ResultList<T>
                     {
                       CenterLatitude = CenterLatitude,
                       CenterLongitude = CenterLongitude,
                       Results = Results.Select(x => x.Clone()).Cast<T>().ToList()
                     };
        return list;
      }
    }
    

    Then to make a deep copy of your object:

    resultList.clone();
    
    0 讨论(0)
提交回复
热议问题