Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 深度克隆对象_C#_.net_Clone - Fatal编程技术网

C# 深度克隆对象

C# 深度克隆对象,c#,.net,clone,C#,.net,Clone,我想做一些类似的事情: MyObject myObj = GetMyObj(); // Create and fill a new object MyObject newObj = myObj.Clone(); 然后对原始对象中未反映的新对象进行更改 我并不经常需要这个功能,所以在必要的时候,我会创建一个新的对象,然后分别复制每个属性,但它总是让我觉得有一种更好或更优雅的方式来处理这种情况 如何克隆或深度复制一个对象,以便在没有任何更改反映在原始对象中的情况下修改克隆的对象?通常,您实现ICl

我想做一些类似的事情:

MyObject myObj = GetMyObj(); // Create and fill a new object
MyObject newObj = myObj.Clone();
然后对原始对象中未反映的新对象进行更改

我并不经常需要这个功能,所以在必要的时候,我会创建一个新的对象,然后分别复制每个属性,但它总是让我觉得有一种更好或更优雅的方式来处理这种情况


如何克隆或深度复制一个对象,以便在没有任何更改反映在原始对象中的情况下修改克隆的对象?

通常,您实现IClonable接口并自行实现克隆。 C#对象有一个内置的MemberwiseClone方法,该方法执行浅层复制,可以帮助您完成所有原语的复制

对于深度复制,它无法知道如何自动执行

  • 基本上,您需要实现IClonable接口,然后实现对象结构复制
  • 如果它是所有成员的深度副本,那么您需要确保(不涉及您选择的解决方案)所有子项都是可克隆的
  • 有时,在这个过程中,您需要注意一些限制,例如,如果您复制ORM对象,大多数框架只允许将一个对象附加到会话,并且您不能克隆该对象,或者如果您可能需要关心这些对象的会话附加

  • 干杯。

    比起克隆,我更喜欢复制构造函数。意图更清楚。

    简单的回答是从IClonable接口继承,然后实现.clone函数。Clone应该执行memberwise复制,并在需要它的任何成员上执行深度复制,然后返回结果对象。这是一个递归操作(它要求要克隆的类的所有成员都是值类型或实现ICloneable,并且它们的成员是值类型或实现ICloneable,依此类推)

    有关使用iClonable进行克隆的更详细说明,请查看

    长话短说的答案是“视情况而定”。正如其他人所提到的,iClonable不受泛型支持,需要对循环类引用进行特殊考虑,并且实际上被一些人视为.NET框架中的一个。序列化方法取决于对象是否可序列化,而这些对象可能不可序列化,并且您可能无法控制。关于哪种做法是“最佳”做法,社会上仍有很多争论。事实上,没有一种解决方案是适用于所有情况的一刀切的最佳实践,就像iClonable最初被解释为的那样


    更多选项请参见本文(归功于Ian)。

    一种方法是实现接口(已描述,因此我不会重复),这里有一个不错的深度克隆对象复制器,我不久前在上面找到,并将其合并到我们的代码中。 正如其他地方提到的,它要求对象是可序列化的

    using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;
    
    /// <summary>
    /// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
    /// Provides a method for performing a deep copy of an object.
    /// Binary Serialization is used to perform the copy.
    /// </summary>
    public static class ObjectCopier
    {
        /// <summary>
        /// Perform a deep copy of the object via serialization.
        /// </summary>
        /// <typeparam name="T">The type of object being copied.</typeparam>
        /// <param name="source">The object instance to copy.</param>
        /// <returns>A deep copy of the object.</returns>
        public static T Clone<T>(T source)
        {
            if (!typeof(T).IsSerializable)
            {
                throw new ArgumentException("The type must be serializable.", nameof(source));
            }
    
            // Don't serialize a null object, simply return the default for that object
            if (ReferenceEquals(self, null)) return default;
    
            using var Stream stream = new MemoryStream();
            IFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, source);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(stream);
        }
    }
    
    不使用的原因是,因为它没有通用接口。它不清楚你得到的是浅拷贝还是深拷贝;这取决于实现者

    是的,
    MemberwiseClone
    制作了一个浅拷贝,但是
    MemberwiseClone
    的反面不是
    Clone
    ;它可能是不存在的DeepClone。当您通过ICloneable接口使用对象时,您无法知道底层对象执行哪种克隆。(XML注释并不能说明这一点,因为您将获得接口注释,而不是对象克隆方法上的注释。)


    我通常只做一个
    复制
    的方法,它完全符合我的要求。

    我想出了这个方法来克服手工深度复制列表的缺点

    我用这个:

    static public IEnumerable<SpotPlacement> CloneList(List<SpotPlacement> spotPlacements)
    {
        foreach (SpotPlacement sp in spotPlacements)
        {
            yield return (SpotPlacement)sp.Clone();
        }
    }
    
    我试图想出一个可以做到这一点的oneliner,但这是不可能的,因为它不能在匿名方法块中工作

    更好的方法是使用通用列表克隆器:

    类实用程序,其中T:ICloneable
    {
    静态公共IEnumerable克隆列表(列表tl)
    {
    foreach(T在tl中)
    {
    产量回报率(T)T.Clone();
    }
    }
    }
    
    我在Silverlight中使用iClonable时遇到问题,但我喜欢seralize的想法,我可以seralize XML,所以我做了以下工作:

    static public class SerializeHelper
    {
        //Michael White, Holly Springs Consulting, 2009
        //michael@hollyspringsconsulting.com
        public static T DeserializeXML<T>(string xmlData) where T:new()
        {
            if (string.IsNullOrEmpty(xmlData))
                return default(T);
    
            TextReader tr = new StringReader(xmlData);
            T DocItms = new T();
            XmlSerializer xms = new XmlSerializer(DocItms.GetType());
            DocItms = (T)xms.Deserialize(tr);
    
            return DocItms == null ? default(T) : DocItms;
        }
    
        public static string SeralizeObjectToXML<T>(T xmlObject)
        {
            StringBuilder sbTR = new StringBuilder();
            XmlSerializer xmsTR = new XmlSerializer(xmlObject.GetType());
            XmlWriterSettings xwsTR = new XmlWriterSettings();
    
            XmlWriter xmwTR = XmlWriter.Create(sbTR, xwsTR);
            xmsTR.Serialize(xmwTR,xmlObject);
    
            return sbTR.ToString();
        }
    
        public static T CloneObject<T>(T objClone) where T:new()
        {
            string GetString = SerializeHelper.SeralizeObjectToXML<T>(objClone);
            return SerializeHelper.DeserializeXML<T>(GetString);
        }
    }
    
    静态公共类序列化帮助器
    {
    //迈克尔·怀特,霍利斯普林斯咨询公司,2009年
    //michael@hollyspringsconsulting.com
    公共静态T反序列化xml(字符串xmlData),其中T:new()
    {
    if(string.IsNullOrEmpty(xmlData))
    返回默认值(T);
    TextReader tr=新的StringReader(xmlData);
    T DocItms=新的T();
    XmlSerializer xms=新的XmlSerializer(DocItms.GetType());
    DocItms=(T)xms.反序列化(tr);
    return DocItms==null?默认值(T):DocItms;
    }
    公共静态字符串SeralizeObjectToXML(T xmlObject)
    {
    StringBuilder sbTR=新的StringBuilder();
    XmlSerializer xmsTR=新的XmlSerializer(xmlObject.GetType());
    xwsTR=新的XmlWriterSettings();
    XmlWriter xmwTR=XmlWriter.Create(sbTR,xwsTR);
    序列化(xmwTR,xmlObject);
    返回sbTR.ToString();
    }
    公共静态T CloneObject(T objClone),其中T:new()
    {
    string GetString=SerializeHelper.SeralizeObjectToXML(objClone);
    返回SerializeHelper.DeserializeXML(GetString);
    }
    }
    
    我也看到它是通过反射实现的。基本上,有一种方法可以遍历对象的成员,并将它们适当地复制到新对象。当它到达引用类型或集合时,我认为它对自身进行了递归调用。反射代价很高,但效果很好。

    复制所有公共属性的简单扩展方法。适用于任何对象,不要求类是
    [可序列化]
    。可扩展为其他访问级别

    public static void CopyTo( this object S, object T )
    {
        foreach( var pS in S.GetType().GetProperties() )
        {
            foreach( var pT in T.GetType().GetProperties() )
            {
                if( pT.Name != pS.Name ) continue;
                ( pT.GetSetMethod() ).Invoke( T, new object[] 
                { pS.GetGetMethod().Invoke( S, null ) } );
            }
        };
    }
    
    这里
    public object Clone()
    {
        OrderItem newOrderItem = new OrderItem();
        ...
        newOrderItem._exactPlacements.AddRange(SpotPlacement.CloneList(_exactPlacements));
        ...
        return newOrderItem;
    }
    
    class Utility<T> where T : ICloneable
    {
        static public IEnumerable<T> CloneList(List<T> tl)
        {
            foreach (T t in tl)
            {
                yield return (T)t.Clone();
            }
        }
    }
    
    static public class SerializeHelper
    {
        //Michael White, Holly Springs Consulting, 2009
        //michael@hollyspringsconsulting.com
        public static T DeserializeXML<T>(string xmlData) where T:new()
        {
            if (string.IsNullOrEmpty(xmlData))
                return default(T);
    
            TextReader tr = new StringReader(xmlData);
            T DocItms = new T();
            XmlSerializer xms = new XmlSerializer(DocItms.GetType());
            DocItms = (T)xms.Deserialize(tr);
    
            return DocItms == null ? default(T) : DocItms;
        }
    
        public static string SeralizeObjectToXML<T>(T xmlObject)
        {
            StringBuilder sbTR = new StringBuilder();
            XmlSerializer xmsTR = new XmlSerializer(xmlObject.GetType());
            XmlWriterSettings xwsTR = new XmlWriterSettings();
    
            XmlWriter xmwTR = XmlWriter.Create(sbTR, xwsTR);
            xmsTR.Serialize(xmwTR,xmlObject);
    
            return sbTR.ToString();
        }
    
        public static T CloneObject<T>(T objClone) where T:new()
        {
            string GetString = SerializeHelper.SeralizeObjectToXML<T>(objClone);
            return SerializeHelper.DeserializeXML<T>(GetString);
        }
    }
    
    public static void CopyTo( this object S, object T )
    {
        foreach( var pS in S.GetType().GetProperties() )
        {
            foreach( var pT in T.GetType().GetProperties() )
            {
                if( pT.Name != pS.Name ) continue;
                ( pT.GetSetMethod() ).Invoke( T, new object[] 
                { pS.GetGetMethod().Invoke( S, null ) } );
            }
        };
    }
    
    public static object CloneObject(object opSource)
    {
        //grab the type and create a new instance of that type
        Type opSourceType = opSource.GetType();
        object opTarget = CreateInstanceOfType(opSourceType);
    
        //grab the properties
        PropertyInfo[] opPropertyInfo = opSourceType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    
        //iterate over the properties and if it has a 'set' method assign it from the source TO the target
        foreach (PropertyInfo item in opPropertyInfo)
        {
            if (item.CanWrite)
            {
                //value types can simply be 'set'
                if (item.PropertyType.IsValueType || item.PropertyType.IsEnum || item.PropertyType.Equals(typeof(System.String)))
                {
                    item.SetValue(opTarget, item.GetValue(opSource, null), null);
                }
                //object/complex types need to recursively call this method until the end of the tree is reached
                else
                {
                    object opPropertyValue = item.GetValue(opSource, null);
                    if (opPropertyValue == null)
                    {
                        item.SetValue(opTarget, null, null);
                    }
                    else
                    {
                        item.SetValue(opTarget, CloneObject(opPropertyValue), null);
                    }
                }
            }
        }
        //return the new item
        return opTarget;
    }
    
    public class Person : ICloneable
    {
        private final Brain brain; // brain is final since I do not want 
                    // any transplant on it once created!
        private int age;
        public Person(Brain aBrain, int theAge)
        {
            brain = aBrain; 
            age = theAge;
        }
        protected Person(Person another)
        {
            Brain refBrain = null;
            try
            {
                refBrain = (Brain) another.brain.clone();
                // You can set the brain in the constructor
            }
            catch(CloneNotSupportedException e) {}
            brain = refBrain;
            age = another.age;
        }
        public String toString()
        {
            return "This is person with " + brain;
            // Not meant to sound rude as it reads!
        }
        public Object clone()
        {
            return new Person(this);
        }
        …
    }
    
    public class SkilledPerson extends Person
    {
        private String theSkills;
        public SkilledPerson(Brain aBrain, int theAge, String skills)
        {
            super(aBrain, theAge);
            theSkills = skills;
        }
        protected SkilledPerson(SkilledPerson another)
        {
            super(another);
            theSkills = another.theSkills;
        }
    
        public Object clone()
        {
            return new SkilledPerson(this);
        }
        public String toString()
        {
            return "SkilledPerson: " + super.toString();
        }
    }
    
    public class User
    {
        public static void play(Person p)
        {
            Person another = (Person) p.clone();
            System.out.println(p);
            System.out.println(another);
        }
        public static void main(String[] args)
        {
            Person sam = new Person(new Brain(), 1);
            play(sam);
            SkilledPerson bob = new SkilledPerson(new SmarterBrain(), 1, "Writer");
            play(bob);
        }
    }
    
    This is person with Brain@1fcc69
    This is person with Brain@253498
    SkilledPerson: This is person with SmarterBrain@1fef6f
    SkilledPerson: This is person with SmarterBrain@209f4e
    
    MyObject oldObj; // The existing object to clone
    
    MyObject newObj = new MyObject();
    newObj.InjectFrom(oldObj); // Using ValueInjecter syntax
    
    public static T Clone<T>(T source)
    {
        var serialized = JsonConvert.SerializeObject(source);
        return JsonConvert.DeserializeObject<T>(serialized);
    }
    
    public static class SystemExtension
    {
        public static T Clone<T>(this T source)
        {
            var serialized = JsonConvert.SerializeObject(source);
            return JsonConvert.DeserializeObject<T>(serialized);
        }
    }
    
    var newInstance = source.GetClone();
    
    var newInstance 
        = source.GetClone(CloningFlags.Properties | CloningFlags.CollectionItems);
    
    .Lambda #Lambda1<System.Func`4[System.Collections.Generic.List`1[System.Int32],CloneExtensions.CloningFlags,System.Collections.Generic.IDictionary`2[System.Type,System.Func`2[System.Object,System.Object]],System.Collections.Generic.List`1[System.Int32]]>(
        System.Collections.Generic.List`1[System.Int32] $source,
        CloneExtensions.CloningFlags $flags,
        System.Collections.Generic.IDictionary`2[System.Type,System.Func`2[System.Object,System.Object]] $initializers) {
        .Block(System.Collections.Generic.List`1[System.Int32] $target) {
            .If ($source == null) {
                .Return #Label1 { null }
            } .Else {
                .Default(System.Void)
            };
            .If (
                .Call $initializers.ContainsKey(.Constant<System.Type>(System.Collections.Generic.List`1[System.Int32]))
            ) {
                $target = (System.Collections.Generic.List`1[System.Int32]).Call ($initializers.Item[.Constant<System.Type>(System.Collections.Generic.List`1[System.Int32])]
                ).Invoke((System.Object)$source)
            } .Else {
                $target = .New System.Collections.Generic.List`1[System.Int32]()
            };
            .If (
                ((System.Byte)$flags & (System.Byte).Constant<CloneExtensions.CloningFlags>(Fields)) == (System.Byte).Constant<CloneExtensions.CloningFlags>(Fields)
            ) {
                .Default(System.Void)
            } .Else {
                .Default(System.Void)
            };
            .If (
                ((System.Byte)$flags & (System.Byte).Constant<CloneExtensions.CloningFlags>(Properties)) == (System.Byte).Constant<CloneExtensions.CloningFlags>(Properties)
            ) {
                .Block() {
                    $target.Capacity = .Call CloneExtensions.CloneFactory.GetClone(
                        $source.Capacity,
                        $flags,
                        $initializers)
                }
            } .Else {
                .Default(System.Void)
            };
            .If (
                ((System.Byte)$flags & (System.Byte).Constant<CloneExtensions.CloningFlags>(CollectionItems)) == (System.Byte).Constant<CloneExtensions.CloningFlags>(CollectionItems)
            ) {
                .Block(
                    System.Collections.Generic.IEnumerator`1[System.Int32] $var1,
                    System.Collections.Generic.ICollection`1[System.Int32] $var2) {
                    $var1 = (System.Collections.Generic.IEnumerator`1[System.Int32]).Call $source.GetEnumerator();
                    $var2 = (System.Collections.Generic.ICollection`1[System.Int32])$target;
                    .Loop  {
                        .If (.Call $var1.MoveNext() != False) {
                            .Call $var2.Add(.Call CloneExtensions.CloneFactory.GetClone(
                                    $var1.Current,
                                    $flags,
    
    
                             $initializers))
                    } .Else {
                        .Break #Label2 { }
                    }
                }
                .LabelTarget #Label2:
            }
        } .Else {
            .Default(System.Void)
        };
        .Label
            $target
        .LabelTarget #Label1:
    }
    
    (source, flags, initializers) =>
    {
        if(source == null)
            return null;
    
        if(initializers.ContainsKey(typeof(List<int>))
            target = (List<int>)initializers[typeof(List<int>)].Invoke((object)source);
        else
            target = new List<int>();
    
        if((flags & CloningFlags.Properties) == CloningFlags.Properties)
        {
            target.Capacity = target.Capacity.GetClone(flags, initializers);
        }
    
        if((flags & CloningFlags.CollectionItems) == CloningFlags.CollectionItems)
        {
            var targetCollection = (ICollection<int>)target;
            foreach(var item in (ICollection<int>)source)
            {
                targetCollection.Add(item.Clone(flags, initializers));
            }
        }
    
        return target;
    }
    
    public static class ObjectCopier
    {
    
        /// <summary>
        /// Perform a deep Copy of an object that is marked with '[Serializable]' or '[DataContract]'
        /// </summary>
        /// <typeparam name="T">The type of object being copied.</typeparam>
        /// <param name="source">The object instance to copy.</param>
        /// <returns>The copied object.</returns>
        public static T Clone<T>(T source)
        {
            if (typeof(T).IsSerializable == true)
            {
                return CloneUsingSerializable<T>(source);
            }
    
            if (IsDataContract(typeof(T)) == true)
            {
                return CloneUsingDataContracts<T>(source);
            }
    
            throw new ArgumentException("The type must be Serializable or use DataContracts.", "source");
        }
    
    
        /// <summary>
        /// Perform a deep Copy of an object that is marked with '[Serializable]'
        /// </summary>
        /// <remarks>
        /// Found on http://stackoverflow.com/questions/78536/cloning-objects-in-c-sharp
        /// Uses code found on CodeProject, which allows free use in third party apps
        /// - http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
        /// </remarks>
        /// <typeparam name="T">The type of object being copied.</typeparam>
        /// <param name="source">The object instance to copy.</param>
        /// <returns>The copied object.</returns>
        public static T CloneUsingSerializable<T>(T source)
        {
            if (!typeof(T).IsSerializable)
            {
                throw new ArgumentException("The type must be serializable.", "source");
            }
    
            // Don't serialize a null object, simply return the default for that object
            if (Object.ReferenceEquals(source, null))
            {
                return default(T);
            }
    
            IFormatter formatter = new BinaryFormatter();
            Stream stream = new MemoryStream();
            using (stream)
            {
                formatter.Serialize(stream, source);
                stream.Seek(0, SeekOrigin.Begin);
                return (T)formatter.Deserialize(stream);
            }
        }
    
    
        /// <summary>
        /// Perform a deep Copy of an object that is marked with '[DataContract]'
        /// </summary>
        /// <typeparam name="T">The type of object being copied.</typeparam>
        /// <param name="source">The object instance to copy.</param>
        /// <returns>The copied object.</returns>
        public static T CloneUsingDataContracts<T>(T source)
        {
            if (IsDataContract(typeof(T)) == false)
            {
                throw new ArgumentException("The type must be a data contract.", "source");
            }
    
            // ** Don't serialize a null object, simply return the default for that object
            if (Object.ReferenceEquals(source, null))
            {
                return default(T);
            }
    
            DataContractSerializer dcs = new DataContractSerializer(typeof(T));
            using(Stream stream = new MemoryStream())
            {
                using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream))
                {
                    dcs.WriteObject(writer, source);
                    writer.Flush();
                    stream.Seek(0, SeekOrigin.Begin);
                    using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max))
                    {
                        return (T)dcs.ReadObject(reader);
                    }
                }
            }
        }
    
    
        /// <summary>
        /// Helper function to check if a class is a [DataContract]
        /// </summary>
        /// <param name="type">The type of the object to check.</param>
        /// <returns>Boolean flag indicating if the class is a DataContract (true) or not (false) </returns>
        public static bool IsDataContract(Type type)
        {
            object[] attributes = type.GetCustomAttributes(typeof(DataContractAttribute), false);
            return attributes.Length == 1;
        }
    
    } 
    
        public AnyObject(AnyObject anyObject)
        {
            foreach (var property in typeof(AnyObject).GetProperties())
            {
                property.SetValue(this, property.GetValue(anyObject));
            }
            foreach (var field in typeof(AnyObject).GetFields())
            {
                field.SetValue(this, field.GetValue(anyObject));
            }
        }
    
    Demo 1 of shallow and deep copy, using classes and MemberwiseClone:
      Create Bob
        Bob.Age=30, Bob.Purchase.Description=Lamborghini
      Clone Bob >> BobsSon
      Adjust BobsSon details
        BobsSon.Age=2, BobsSon.Purchase.Description=Toy car
      Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:
        Bob.Age=30, Bob.Purchase.Description=Lamborghini
      Elapsed time: 00:00:04.7795670,30000000
    
    Demo 2 of shallow and deep copy, using structs and value copying:
      Create Bob
        Bob.Age=30, Bob.Purchase.Description=Lamborghini
      Clone Bob >> BobsSon
      Adjust BobsSon details:
        BobsSon.Age=2, BobsSon.Purchase.Description=Toy car
      Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:
        Bob.Age=30, Bob.Purchase.Description=Lamborghini
      Elapsed time: 00:00:01.0875454,30000000
    
    Demo 3 of deep copy, using class and serialize/deserialize:
      Elapsed time: 00:00:39.9339425,30000000
    
    // Nested MemberwiseClone example. 
    // Added to demo how to deep copy a reference class.
    [Serializable] // Not required if using MemberwiseClone, only used for speed comparison using serialization.
    public class Person
    {
        public Person(int age, string description)
        {
            this.Age = age;
            this.Purchase.Description = description;
        }
        [Serializable] // Not required if using MemberwiseClone
        public class PurchaseType
        {
            public string Description;
            public PurchaseType ShallowCopy()
            {
                return (PurchaseType)this.MemberwiseClone();
            }
        }
        public PurchaseType Purchase = new PurchaseType();
        public int Age;
        // Add this if using nested MemberwiseClone.
        // This is a class, which is a reference type, so cloning is more difficult.
        public Person ShallowCopy()
        {
            return (Person)this.MemberwiseClone();
        }
        // Add this if using nested MemberwiseClone.
        // This is a class, which is a reference type, so cloning is more difficult.
        public Person DeepCopy()
        {
                // Clone the root ...
            Person other = (Person) this.MemberwiseClone();
                // ... then clone the nested class.
            other.Purchase = this.Purchase.ShallowCopy();
            return other;
        }
    }
    // Added to demo how to copy a value struct (this is easy - a deep copy happens by default)
    public struct PersonStruct
    {
        public PersonStruct(int age, string description)
        {
            this.Age = age;
            this.Purchase.Description = description;
        }
        public struct PurchaseType
        {
            public string Description;
        }
        public PurchaseType Purchase;
        public int Age;
        // This is a struct, which is a value type, so everything is a clone by default.
        public PersonStruct ShallowCopy()
        {
            return (PersonStruct)this;
        }
        // This is a struct, which is a value type, so everything is a clone by default.
        public PersonStruct DeepCopy()
        {
            return (PersonStruct)this;
        }
    }
    // Added only for a speed comparison.
    public class MyDeepCopy
    {
        public static T DeepCopy<T>(T obj)
        {
            object result = null;
            using (var ms = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(ms, obj);
                ms.Position = 0;
                result = (T)formatter.Deserialize(ms);
                ms.Close();
            }
            return (T)result;
        }
    }
    
    void MyMain(string[] args)
    {
        {
            Console.Write("Demo 1 of shallow and deep copy, using classes and MemberwiseCopy:\n");
            var Bob = new Person(30, "Lamborghini");
            Console.Write("  Create Bob\n");
            Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
            Console.Write("  Clone Bob >> BobsSon\n");
            var BobsSon = Bob.DeepCopy();
            Console.Write("  Adjust BobsSon details\n");
            BobsSon.Age = 2;
            BobsSon.Purchase.Description = "Toy car";
            Console.Write("    BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);
            Console.Write("  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");
            Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
            Debug.Assert(Bob.Age == 30);
            Debug.Assert(Bob.Purchase.Description == "Lamborghini");
            var sw = new Stopwatch();
            sw.Start();
            int total = 0;
            for (int i = 0; i < 100000; i++)
            {
                var n = Bob.DeepCopy();
                total += n.Age;
            }
            Console.Write("  Elapsed time: {0},{1}\n\n", sw.Elapsed, total);
        }
        {               
            Console.Write("Demo 2 of shallow and deep copy, using structs:\n");
            var Bob = new PersonStruct(30, "Lamborghini");
            Console.Write("  Create Bob\n");
            Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
            Console.Write("  Clone Bob >> BobsSon\n");
            var BobsSon = Bob.DeepCopy();
            Console.Write("  Adjust BobsSon details:\n");
            BobsSon.Age = 2;
            BobsSon.Purchase.Description = "Toy car";
            Console.Write("    BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);
            Console.Write("  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");
            Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);                
            Debug.Assert(Bob.Age == 30);
            Debug.Assert(Bob.Purchase.Description == "Lamborghini");
            var sw = new Stopwatch();
            sw.Start();
            int total = 0;
            for (int i = 0; i < 100000; i++)
            {
                var n = Bob.DeepCopy();
                total += n.Age;
            }
            Console.Write("  Elapsed time: {0},{1}\n\n", sw.Elapsed, total);
        }
        {
            Console.Write("Demo 3 of deep copy, using class and serialize/deserialize:\n");
            int total = 0;
            var sw = new Stopwatch();
            sw.Start();
            var Bob = new Person(30, "Lamborghini");
            for (int i = 0; i < 100000; i++)
            {
                var BobsSon = MyDeepCopy.DeepCopy<Person>(Bob);
                total += BobsSon.Age;
            }
            Console.Write("  Elapsed time: {0},{1}\n", sw.Elapsed, total);
        }
        Console.ReadKey();
    }
    
    public class Person 
    {
      [DeepClone(DeepCloneBehavior.Shallow)]
      private Job _currentJob;      
    
      public string Name { get; set; }
    
      public Job CurrentJob 
      { 
        get{ return _currentJob; }
        set{ _currentJob = value; }
      }
    
      public Person Manager { get; set; }
    }
    
    public class Address 
    {      
      public Person PersonLivingHere { get; set; }
    }
    
    Address adr = new Address();
    adr.PersonLivingHere = new Person("John");
    adr.PersonLivingHere.BestFriend = new Person("James");
    adr.PersonLivingHere.CurrentJob = new Job("Programmer");
    
    Address adrClone = adr.Clone();
    
    //RESULT
    adr.PersonLivingHere == adrClone.PersonLivingHere //false
    adr.PersonLivingHere.Manager == adrClone.PersonLivingHere.Manager //false
    adr.PersonLivingHere.CurrentJob == adrClone.PersonLivingHere.CurrentJob //true
    adr.PersonLivingHere.CurrentJob.AnyProperty == adrClone.PersonLivingHere.CurrentJob.AnyProperty //true
    
    private static MyObj DeepCopy(MyObj source)
            {
    
                var DeserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
    
                return JsonConvert.DeserializeObject<MyObj >(JsonConvert.SerializeObject(source), DeserializeSettings);
    
            }
    
    MyType source = new MyType();
    Mapper.CreateMap<MyType, MyType>();
    MyType target = Mapper.Map<MyType, MyType>(source);
    
    public static T Copy<T>(this T source)
    {
        T copy = default(T);
        Mapper.CreateMap<T, T>();
        copy = Mapper.Map<T, T>(source);
        return copy;
    }
    
    MyType copy = source.Copy();
    
    public partial class Root : ICloneable
    {
        public Root(int number)
        {
            _number = number;
        }
        private int _number;
    
        public Partial[] Partials { get; set; }
    
        public IList<ulong> Numbers { get; set; }
    
        public object Clone()
        {
            return Clone(true);
        }
    
        private Root()
        {
        }
    } 
    
    public partial class Root
    {
        public Root Clone(bool deep)
        {
            var copy = new Root();
            // All value types can be simply copied
            copy._number = _number; 
            if (deep)
            {
                // In a deep clone the references are cloned 
                var tempPartials = new Partial[Partials.Length];
                for (var i = 0; i < Partials.Length; i++)
                {
                    var value = Partials[i];
                    value = value.Clone(true);
                    tempPartials[i] = value;
                }
                copy.Partials = tempPartials;
                var tempNumbers = new List<ulong>(Numbers.Count);
                for (var i = 0; i < Numbers.Count; i++)
                {
                    var value = Numbers[i];
                    tempNumbers.Add(value);
                }
                copy.Numbers = tempNumbers;
            }
            else
            {
                // In a shallow clone only references are copied
                copy.Partials = Partials; 
                copy.Numbers = Numbers; 
            }
            return copy;
        }
    }
    
    public class MyClass
    {
        public virtual MyClass DeepClone()
        {
            var returnObj = (MyClass)MemberwiseClone();
            var type = returnObj.GetType();
            var fieldInfoArray = type.GetRuntimeFields().ToArray();
    
            foreach (var fieldInfo in fieldInfoArray)
            {
                object sourceFieldValue = fieldInfo.GetValue(this);
                if (!(sourceFieldValue is MyClass))
                {
                    continue;
                }
    
                var sourceObj = (MyClass)sourceFieldValue;
                var clonedObj = sourceObj.DeepClone();
                fieldInfo.SetValue(returnObj, clonedObj);
            }
            return returnObj;
        }
    }
    
        using System.Linq;
        using System.Reflection;
    
    public MyClass Clone(MyClass theObjectIneededToClone)
    {
        MyClass clonedObj = theObjectIneededToClone.DeepClone();
    }
    
    public static T DeepClone<T>(this T originalObject)
    { /* the cloning code */ }
    
    var copy = anyObject.DeepClone();
    
    MyObject myObj = GetMyObj(); // Create and fill a new object
    MyObject newObj = new MyObject(myObj); //DeepClone it
    
    public static T Clone<T>(this T theObject)
    {
        string jsonData = JsonConvert.SerializeObject(theObject);
        return JsonConvert.DeserializeObject<T>(jsonData);
    }
    
    NewObject = OldObject.Clone();