一个C#对象的深层副本(Deep Copy of a C# Object)

2019-06-25 13:21发布

我的工作是用C#编写一些代码。 在这个程序,我有一个自定义集合定义如下:

public class ResultList<T> : IEnumerable<T>
{
  public List<T> Results { get; set; }
  public decimal CenterLatitude { get; set; }
  public decimal CenterLongitude { get; set; }
}

由结果所使用的类型是三个自定义类型中的一种。 每个自定义类型的属性只是基本类型(整数,字符串,布尔变量,INT?布尔?)。 下面是自定义类型的一个示例:

public class ResultItem
{
  public int ID { get; set; }
  public string Name { get; set; }
  public bool? isLegit { get; set; }
}

我如何执行我创建了一个ResultList对象的深副本。 我发现这个职位: 通用方法来创建一个集合中的所有元素的深层副本 。 然而,我无法弄清楚如何做到这一点。

Answer 1:

其中一个为什么你ResultList类不会乔恩斯基特的工作原因, 例如是因为它没有实现ICloneable接口。

实现ICloneable在您需要克隆的所有类,如

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

而且还对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;
  }
}

然后让你的对象的深层副本:

resultList.clone();


Answer 2:

涉及至少编码工作的方法是,序列化,并通过反序列化的BinaryFormatter

你可以定义下面的扩展方法(摘自Kilhoffer的答案 ):

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

...然后只要致电:

ResultList<T> clone = DeepClone(original);


Answer 3:

扩大对@格奥尔基 - 这,我不得不修改自己的代码来处理其类型继承列表属性:

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


Answer 4:

这里是什么,我需要和写的,它使用反射来每个属性复制(和私人的,如果指定)

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


文章来源: Deep Copy of a C# Object
标签: c# deep-copy