码迷,mamicode.com
首页 > Windows程序 > 详细

c# 实现深浅克隆的方式

时间:2019-10-11 18:07:15      阅读:103      评论:0      收藏:0      [点我收藏+]

标签:cst   obj   his   string   interface   container   引用   处理   add   

在C#中克隆对象的基类

步骤:

  1. 对于该类中的每个字段,请询问其是否支持该ICloneable接口。
  2. 如果该字段不支持该ICloneable接口,则以常规方式设置该字段,这意味着如果该字段是值类型,则将复制该值,但是如果该字段是引用类型,则将克隆字段将指向同一对象。
  3. 如果字段支持该ICloneable接口,则使用其Clone方法在克隆对象中进行设置。
  4. 如果该字段支持该IEnumerable接口,那么我们需要检查它是否支持IListIDictionary 接口。如果是这样,那么我们将迭代该集合,并针对集合中的每个项目询问其是否支持该ICloneable接口。
/// <summary>
/// BaseObject类是一个用来继承的抽象类。 
/// 每一个由此类继承而来的类将自动支持克隆方法。
/// 该类实现了Icloneable接口,并且每个从该对象继承而来的对象都将同样地
/// 支持Icloneable接口。 
/// </summary> 
public abstract class BaseObject : ICloneable
{
    /// <summary>    
    /// 克隆对象,并返回一个已克隆对象的引用    
    /// </summary>    
    /// <returns>引用新的克隆对象</returns>     
    public object Clone()
    {
        //首先我们建立指定类型的一个实例         
        object newObject = Activator.CreateInstance(this.GetType());
        //我们取得新的类型实例的字段数组。         
        FieldInfo[] fields = newObject.GetType().GetFields();
        int i = 0;
        foreach (FieldInfo fi in this.GetType().GetFields())
        {
            //我们判断字段是否支持ICloneable接口。             
            Type ICloneType = fi.FieldType.GetInterface("ICloneable", true);
            if (ICloneType != null)
            {
                //取得对象的Icloneable接口。                 
                ICloneable IClone = (ICloneable)fi.GetValue(this);
                //我们使用克隆方法给字段设定新值。                
                fields[i].SetValue(newObject, IClone.Clone());
            }
            else
            {
                // 如果该字段部支持Icloneable接口,直接设置即可。                 
                fields[i].SetValue(newObject, fi.GetValue(this));
            }
            //现在我们检查该对象是否支持IEnumerable接口,如果支持,             
            //我们还需要枚举其所有项并检查他们是否支持IList 或 IDictionary 接口。            
            Type IEnumerableType = fi.FieldType.GetInterface("IEnumerable", true);
            if (IEnumerableType != null)
            {
                //取得该字段的IEnumerable接口                
                IEnumerable IEnum = (IEnumerable)fi.GetValue(this);
                Type IListType = fields[i].FieldType.GetInterface("IList", true);
                Type IDicType = fields[i].FieldType.GetInterface("IDictionary", true);
                int j = 0;
                if (IListType != null)
                {
                    //取得IList接口。                     
                    IList list = (IList)fields[i].GetValue(newObject);
                    foreach (object obj in IEnum)
                    {
                        //查看当前项是否支持支持ICloneable 接口。                         
                        ICloneType = obj.GetType().GetInterface("ICloneable", true);
                        if (ICloneType != null)
                        {
                            //如果支持ICloneable 接口,    
                            //我们用它李设置列表中的对象的克隆    
                            ICloneable clone = (ICloneable)obj;
                            list[j] = clone.Clone();
                        }
                        //注意:如果列表中的项不支持ICloneable接口,那么                      
                        //在克隆列表的项将与原列表对应项相同                      
                        //(只要该类型是引用类型)                        
                        j++;
                    }
                }
                else if (IDicType != null)
                {
                    //取得IDictionary 接口                    
                    IDictionary dic = (IDictionary)fields[i].GetValue(newObject);
                    j = 0;
                    foreach (DictionaryEntry de in IEnum)
                    {
                        //查看当前项是否支持支持ICloneable 接口。                         
                        ICloneType = de.Value.GetType().
                            GetInterface("ICloneable", true);
                        if (ICloneType != null)
                        {
                            ICloneable clone = (ICloneable)de.Value;
                            dic[de.Key] = clone.Clone();
                        }
                        j++;
                    }
                }
            }
            i++;
        }
        return newObject;
    }
}
如何使用
public class MyClass : BaseObject
{
    public string myStr ="test";
    public int id;
}

public class MyContainer : BaseObject
{
    public string name = "test2";
    public MyClass[] myArray= new MyClass[5];

    public class MyContainer()
    {
        for(int i=0 ; i<5 ; i++)
        {
             this.myArray[I] = new MyClass();
        }
    }
}
//Now in the Main method you can do the following:

static void Main(string[] args)
{
    MyContainer con1 = new MyContainer();
    MyContainer con2 = (MyContainer)con1.Clone();

   con2.myArray[0].id = 5;
}

最简单的对象克隆

/*
 * By - Rahul Dantkale
 * Company - Indigo Architects
 * 
 */
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;     
      
public static class ObjectClone
{
    public static T Clone<T>(T RealObject)
    {
        using (Stream objectStream = new MemoryStream())
        {
            IFormatter formatter = new BinaryFormatter();
            formatter.Serialize(objectStream, RealObject);
            objectStream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(objectStream);
        }
    }
}
Using the code

All you have to do is to add reference to CloneManager project and create an instance of this class in your source code as shows below.

Code Example:

//Create an instance of clone manager
IClone cloneManager = new CloneManager();

MyClass newInstance = cloneManager.Clone(instance);
Implementation

The CloneManager implements IClone interface which exposes only one method. The Clone method simply serialize the instance into a memory stream and deserialize this stream to a new instance of object using XmlSerializer and returns that to the caller.

public interface IClone 
{ 
    T Clone(T instance) where T : class; 
}



using System;
using System.Xml.Serialization;
using System.IO;

namespace Demo.Clone
{
    public class CloneManager:IClone
    {
        /// Clones the specified instance. 
        /// Returns a new instance of an object.
        T IClone.Clone(T instance){
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            MemoryStream stream = new MemoryStream();
            serializer.Serialize(stream, instance);
            stream.Seek(0, SeekOrigin.Begin);
            return serializer.Deserialize(stream) as T;
        }
    }
}
C#中实现对象的深拷贝(Deep Copy)
class CsToD
{
   //基本思想是:一个对象所占据的内存空间,取决于它的实例字段(包括继承树上的私有实例字段) 
   public T DeepCloneObject<T>(T obj) where T : class
   {
      //System.String类型似乎比较特殊,复制它的所有字段,并不能复制它本身 
      //不过由于System.String的不可变性,即使指向同一对象,也无所谓 
      //而且.NET里本来就用字符串池来维持 
      if (obj == null || obj.GetType() == typeof(string))
      return obj;
      object newObj = null;
      try
      {
         //尝试调用默认构造函数 
         newObj = Activator.CreateInstance(obj.GetType());
      }
      catch
      {
         //失败的话,只好枚举构造函数了 
         foreach (ConstructorInfo ci in obj.GetType().GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
         {
            try
            {
               ParameterInfo[] pis = ci.GetParameters();
               object[] objs = new object[pis.Length];
               for (int i = 0; i < pis.Length; i++)
               {
                  if (pis[i].ParameterType.IsValueType)
                  objs[i] = Activator.CreateInstance(pis[i].ParameterType);
                  else
                  //参数类型可能是抽象类或接口,难以实例化 
                  //我能想到的就是枚举应用程序域里的程序集,找到实现了该抽象类或接口的类 
                  //但显然过于复杂了 
                  objs[i] = null;
               }
               newObj = ci.Invoke(objs);
               //无论调用哪个构造函数,只要成功就行了 
               break;
            }
            catch
            {
            }
         }
      }
      foreach (FieldInfo fi in obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
      {
         if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
         fi.SetValue(newObj, fi.GetValue(obj));
         else
         fi.SetValue(newObj, DeepCloneObject(fi.GetValue(obj)));
      }
      //基类的私有实例字段在子类里检索不到,但它仍占据子类对象的内存空间 
      Deep(newObj, obj);
      return (T)newObj;
   }
   
   //克隆继承树上的私有实例字段 
   public void Deep(object newObj, object obj)
   {
      for (Type father = newObj.GetType().BaseType; father != typeof(object); father = father.BaseType)
      {
         foreach (FieldInfo fi in father.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
         {
            //只需要处理私有字段,因为非私有成员已经在子类处理过了 
            if (fi.IsPrivate)
            {
               if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
               {
                  fi.SetValue(newObj, fi.GetValue(obj));
               }
               else
               {
                  fi.SetValue(newObj, DeepCloneObject(fi.GetValue(obj)));
               }
            }
         }
      }
   }
}

c# 实现深浅克隆的方式

标签:cst   obj   his   string   interface   container   引用   处理   add   

原文地址:https://www.cnblogs.com/King2019Blog/p/11655751.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!