How to deep copy a class without marking it as Serializable

前端 未结 7 488
自闭症患者
自闭症患者 2021-01-04 00:09

Given the following class:

class A
{
    public List ListB;

    // etc...
}

where B is another class that may inheri

相关标签:
7条回答
  • 2021-01-04 00:33

    Try using a memory stream to get a deep copy of your object:

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

    Here is more.

    0 讨论(0)
  • 2021-01-04 00:35
        private interface IDeepCopy<T> where T : class
        {
            T DeepCopy();
        }
    
        private class MyClass : IDeepCopy<MyClass>
        {
            public MyClass DeepCopy()
            {
                return (MyClass)this.MemberwiseClone();
            }
        }
    

    Pluss: Yoy can control copy process (if your class has identifier property you can set them, or you can write other business logic code)


    Minus: class can be marked as sealed


    0 讨论(0)
  • 2021-01-04 00:38

    You can try this. It works for me

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

    Thanks to DetoX83 article on code project.

    0 讨论(0)
  • 2021-01-04 00:40

    Can't you do this?

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

    And then refer to How do you do a deep copy of an object in .NET (C# specifically)? for a cloning function

    0 讨论(0)
  • 2021-01-04 00:40

    your interface IDeepCopy is exactly what ICloneable specifies.

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

    and with more friendly implementation :

    class B : ICloneable
    {
         public B Clone() { return new B(); }
         // explicit implementation of ICloneable
         object ICloneable.Clone() { return this.Clone(); }
    }
    
    0 讨论(0)
  • 2021-01-04 00:41

    I stopped using serialization for deep copying anyway, because there is not enough control (not every class needs to be copied the same way). Then I started to implement my own deep copy interfaces and copy every property in the way it should be copied.

    Typical ways to copy a referenced type:

    • use copy constructor
    • use factory method (eg. immutable types)
    • use your own "Clone"
    • copy only reference (eg. other Root-Type)
    • create new instance and copy properties (eg. types not written by yourself lacking a copy constructor)

    Example:

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

    You may think that this a huge amount of work. But at the end, it is easy and straight forward, can be tuned where needed and does exactly what you need.

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