• 话谈c#拷贝


      c#中类型分为值类型和引用类型,值类型对象赋值是本身就是赋的自身的一个副本,而引用类型赋值时则赋的是指向堆上的内存,假如我们不想赋这个地址而想将对象赋过去要怎么做呢?首先要知道拷贝分为浅表拷贝和深层拷贝,浅表拷贝得到一个新的实例,一个与原始对象类型相同、值类型字段相同的拷贝。但是,如果字段是引用类型的,则拷贝的是该引用, 而不是的对象。若想将引用字段的对象也拷贝过去,则称为深拷贝。 为了实现拷贝,本文总结了以下几种方法。

    1.首先就是最笨的方法,传说中的“人工拷贝”,就是将引用里的所有值对象和具有值特征的string对象一一赋给新对象,这种方式代码量过大而且维护起来相当麻烦,所以能不用就不用。

    2.System.Object提供了受保护的方法 MemberwiseClone,可用来实现“浅表”拷贝。由于该方法标记为“受保护”级别,因此,我们只能在继承类或该类内部才能访问该方法。

     public class A
        {
            public string rr { get; set; }
            public string tt { get; set; }
    
    
            public A ShallowCopy()
            {
                return (A)this.MemberwiseClone();
            }
    
        }

    3.使用序列化与反序列化的方式,这种方式虽可实现深度拷贝,但有点大炮打蚊子的味道,而且在外面引用时一定要记得关闭所创建的MemoryStream

     public static object Clone(object o,out MemoryStream ms)
            {
                BinaryFormatter bf = new BinaryFormatter();
               
                ms = new MemoryStream();
                bf.Serialize(ms,o);
                ms.Seek(0, SeekOrigin.Begin);
    
                return bf.Deserialize(ms);
            }

    4.在一个外国人写的博客中(http://www.codeproject.com/Articles/3441/Base-class-for-cloning-an-object-in-C),使用反射的方法来解决了这个问题。他写了一个BaseObject类,如果我们继承这个类就可以实现深度拷贝,下面是他的实现方法:

    创建一个实现 ICloneable 接口的有默认行为的抽象类,所谓的默认行为就是使用以下库函数来拷贝类里的每一个字段。

    1.遍历类里的每个字段,看看是否支持ICloneable接口。

    2.如果不支持ICloneable接口,按下面规则进行设置,也就是说如果字段是个值类型,那将其拷贝,如果是引用类型则拷贝字段指向通一个对象。

    3.如果支持ICloneable,在科隆对象中使用它的克隆方法进行设置。

    4.如果字段支持IEnumerable接口,需要看看它是否支持IList或者IDirectionary接口,如果支持,迭代集合看看是否支持ICloneable接口。

    我们所要做的就是使得所有字段支持ICloneable接口。

    下面是测试结果:

    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();
            }
        }
    }
    static void Main(string[] args)
    {
        MyContainer con1 = new MyContainer();
        MyContainer con2 = (MyContainer)con1.Clone();
    
       con2.myArray[0].id = 5;
    }

    con2中MyClass实例中第一个元素变成了5,但con1没有改变,即实现了深拷贝。

    BaseObject的实现:

    /// <summary>
    /// BaseObject class is an abstract class for you to derive from.
    /// Every class that will be dirived from this class will support the 
    /// Clone method automaticly.<br>
    /// The class implements the interface ICloneable and there 
    /// for every object that will be derived <br>
    /// from this object will support the ICloneable interface as well.
    /// </summary>
    
    public abstract class BaseObject : ICloneable
    {
        /// <summary>
        /// Clone the object, and returning a reference to a cloned object.
        /// </summary>
        /// <returns>Reference to the new cloned 
        /// object.</returns>
        public object Clone()
        {
            //First we create an instance of this specific type.
            object newObject  = Activator.CreateInstance( this.GetType() );
    
            //We get the array of fields for the new type instance.
            FieldInfo[] fields = newObject.GetType().GetFields();
    
            int i = 0;
    
            foreach( FieldInfo fi in this.GetType().GetFields() )
            {
                //We query if the fiels support the ICloneable interface.
                Type ICloneType = fi.FieldType.
                            GetInterface( "ICloneable" , true );
    
                if( ICloneType != null )
                {
                    //Getting the ICloneable interface from the object.
                    ICloneable IClone = (ICloneable)fi.GetValue(this);
    
                    //We use the clone method to set the new value to the field.
                    fields[i].SetValue( newObject , IClone.Clone() );
                }
                else
                {
                    // If the field doesn't support the ICloneable 
                    // interface then just set it.
                    fields[i].SetValue( newObject , fi.GetValue(this) );
                }
    
                //Now we check if the object support the 
                //IEnumerable interface, so if it does
                //we need to enumerate all its items and check if 
                //they support the ICloneable interface.
                Type IEnumerableType = fi.FieldType.GetInterface
                                ( "IEnumerable" , true );
                if( IEnumerableType != null )
                {
                    //Get the IEnumerable interface from the field.
                    IEnumerable IEnum = (IEnumerable)fi.GetValue(this);
    
                    //This version support the IList and the 
                    //IDictionary interfaces to iterate on collections.
                    Type IListType = fields[i].FieldType.GetInterface
                                        ( "IList" , true );
                    Type IDicType = fields[i].FieldType.GetInterface
                                        ( "IDictionary" , true );
    
                    int j = 0;
                    if( IListType != null )
                    {
                        //Getting the IList interface.
                        IList list = (IList)fields[i].GetValue(newObject);
    
                        foreach( object obj in IEnum )
                        {
                            //Checking to see if the current item 
                            //support the ICloneable interface.
                            ICloneType = obj.GetType().
                                GetInterface( "ICloneable" , true );
                            
                            if( ICloneType != null )
                            {
                                //If it does support the ICloneable interface, 
                                //we use it to set the clone of
                                //the object in the list.
                                ICloneable clone = (ICloneable)obj;
    
                                list[j] = clone.Clone();
                            }
    
                            //NOTE: If the item in the list is not 
                            //support the ICloneable interface then in the 
                            //cloned list this item will be the same 
                            //item as in the original list
                            //(as long as this type is a reference type).
    
                            j++;
                        }
                    }
                    else if( IDicType != null )
                    {
                        //Getting the dictionary interface.
                        IDictionary dic = (IDictionary)fields[i].
                                            GetValue(newObject);
                        j = 0;
                        
                        foreach( DictionaryEntry de in IEnum )
                        {
                            //Checking to see if the item 
                            //support the ICloneable interface.
                            ICloneType = de.Value.GetType().
                                GetInterface( "ICloneable" , true );
    
                            if( ICloneType != null )
                            {
                                ICloneable clone = (ICloneable)de.Value;
    
                                dic[de.Key] = clone.Clone();
                            }
                            j++;
                        }
                    }
                }
                i++;
            }
            return newObject;
        }
    }
  • 相关阅读:
    Metasploit:一颗没有发现的珍珠
    每个人都用自己的方式去爱自己在乎的人
    设计模式学习使用go实现原型模式 Zhan
    设计模式学习使用go实现代理模式 Zhan
    设计模式学习使用go实现桥接模式 Zhan
    设计模式学习使用go实现建造者模式 Zhan
    多internet出口浮动静态+IP SLA track
    使用 IP SLA 跟踪配置基于策略的路由 (PBR) 自动重定向流量
    使用IP SLA配置静态路由跟踪(基本)
    (转)PBR路由策略配置
  • 原文地址:https://www.cnblogs.com/xuekai-to-sharp/p/3528106.html
Copyright © 2020-2023  润新知