19

给定以下课程:

class A
{
    public List<B> ListB;

    // etc...
}

B另一个类可能继承/包含其他一些类在哪里。


鉴于这种情况:

  1. A是一个大类,包含许多引用类型
  2. 我无法标记B[Serializable]我无权访问源代码B

以下执行深度复制的方法不起作用:

  1. 我不能使用ICloneableMemberwiseClone作为类A包含许多引用类型
  2. 我无法为 编写复制构造函数A,因为该类很大并且不断被添加,并且包含B无法深度复制的类(如 )
  3. 我无法使用序列化,因为我无法将包含的类(例如B,没有可用源代码的类)标记为[Serializable]

我怎样才能深拷贝课A

4

7 回答 7

10

无论如何,我停止使用序列化进行深度复制,因为没有足够的控制(不是每个类都需要以相同的方式复制)。然后我开始实现自己的深拷贝接口,并以应该复制的方式复制每个属性。

复制引用类型的典型方法:

  • 使用复制构造函数
  • 使用工厂方法(例如不可变类型)
  • 使用你自己的“克隆”
  • 仅复制参考(例如其他根类型)
  • 创建新实例并复制属性(例如,不是您自己编写的类型缺少复制构造函数)

例子:

class A
{
  // copy constructor
  public A(A copy) {}
}

// a referenced class implementing 
class B : IDeepCopy
{
  object Copy() { return new B(); }
}

class C : IDeepCopy
{
  A A;
  B B;
  object Copy()
  {
    C copy = new C();

    // copy property by property in a appropriate way
    copy.A = new A(this.A);
    copy.B = this.B.Copy();
  }
}

你可能认为这是一项巨大的工作。但最后,它很简单直接,可以在需要的地方进行调整,并完全按照您的需要进行。

于 2010-03-30T12:46:50.523 回答
3

你可以试试这个。这个对我有用

    public static object DeepCopy(object obj)
    {
        if (obj == null)
            return null;
        Type type = obj.GetType();

        if (type.IsValueType || type == typeof(string))
        {
            return obj;
        }
        else if (type.IsArray)
        {
            Type elementType = Type.GetType(
                 type.FullName.Replace("[]", string.Empty));
            var array = obj as Array;
            Array copied = Array.CreateInstance(elementType, array.Length);
            for (int i = 0; i < array.Length; i++)
            {
                copied.SetValue(DeepCopy(array.GetValue(i)), i);
            }
            return Convert.ChangeType(copied, obj.GetType());
        }
        else if (type.IsClass)
        {

            object toret = Activator.CreateInstance(obj.GetType());
            FieldInfo[] fields = type.GetFields(BindingFlags.Public |
                        BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (FieldInfo field in fields)
            {
                object fieldValue = field.GetValue(obj);
                if (fieldValue == null)
                    continue;
                field.SetValue(toret, DeepCopy(fieldValue));
            }
            return toret;
        }
        else
            throw new ArgumentException("Unknown type");
    }

感谢 DetoX83关于代码项目的文章。

于 2012-04-01T03:44:11.307 回答
0

你不能这样做吗?

[Serializable]
class A
{
     ...
    [NonSerialized]
    public List<B> ListB;
    ....
}

然后参考How do you do a deep copy of an object in .NET(特别是 C#)?用于克隆功能

于 2010-03-30T12:31:13.340 回答
0

您的界面 IDeepCopy 正是ICloneable指定的。

class B : ICloneable
{
     public object Clone() { return new B(); }
}

并具有更友好的实施:

class B : ICloneable
{
     public B Clone() { return new B(); }
     // explicit implementation of ICloneable
     object ICloneable.Clone() { return this.Clone(); }
}
于 2010-09-08T21:37:03.710 回答
0
    private interface IDeepCopy<T> where T : class
    {
        T DeepCopy();
    }

    private class MyClass : IDeepCopy<MyClass>
    {
        public MyClass DeepCopy()
        {
            return (MyClass)this.MemberwiseClone();
        }
    }

加号: Yoy可以控制复制过程(如果你的类有标识符属性你可以设置它们,或者你可以编写其他业务逻辑代码)


减号:类可以标记为密封


于 2013-02-15T18:59:39.667 回答
0

尝试使用内存流来获取对象的深层副本:

 public static T MyDeepCopy<T>(this T source)
            {
                try
                {

                    //Throw if passed object has nothing
                    if (source == null) { throw new Exception("Null Object cannot be cloned"); }

                    // Don't serialize a null object, simply return the default for that object
                    if (Object.ReferenceEquals(source, null))
                    {
                        return default(T);
                    }

                    //variable declaration
                    T copy;
                    var obj = new DataContractSerializer(typeof(T));
                    using (var memStream = new MemoryStream())
                    {
                        obj.WriteObject(memStream, source);
                        memStream.Seek(0, SeekOrigin.Begin);
                        copy = (T)obj.ReadObject(memStream);
                    }
                    return copy;
                }
                catch (Exception)
                {
                    throw;
                }
            }

这里还有更多。

于 2017-03-29T13:12:29.040 回答
-1

来自另一个线程的答案是使用 json 序列化是我见过的最好的。

public static T CloneJson<T>(this T source)
{      
    if (Object.ReferenceEquals(source, null))
    {
        return default(T);
    }    
    return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source));
}
于 2015-10-14T16:01:17.093 回答