zoukankan      html  css  js  c++  java
  • C# 对象拷贝问题 =等同于浅拷贝

    大家都知道,在C#中变量的存储分为值类型和引用类型两种,而值类型和引用类型在数值变化是产生的后果是不一样的,值类型我们可以轻松实现数值的拷贝,那么引用类型呢,在对象拷贝上存在着一定的难度。

        下面我么从一个经典的例子谈起。
    private void  doChange(string a)
      {
       int b = a;
       b = "2";
       System.Console.WriteLine(b);
       System.Console.WriteLine(a);
      }
    当我么调用上面的函数doChange("1")以后,输出的结果是多少呢?很多大哥开到我提问这个问题,一定气得要骂街了,呵呵,很简单,输出结果是:
    2
    1
    那么我们再看看下面的一个例子
    public class data
      pubic string key ="1"
    }
    private void  doChange(data a)
      {
       data b = a;
       b.key = "2";
       System.Console.WriteLine(b.key.ToString());
       System.Console.WriteLine(a.key.ToString());
      }
    我们再次调用doChange(new data),它的输出结果又是怎么样的呢?
    有些人说:
    2
    1
    如果你也是这么想的,那你就错了,呵呵!正确结果是……
    2
    2
    为什么会是这样呢?很多人一定很奇怪,之所以会出现这样的问题,就和值类型和引用类型有关,第一个值函数的string 本身是个值类型,他在存储的时候,是直接开辟了一个存储空间,而第二个data类型的在存储的时候,其实是通过指针将变量和其存储空间链接在了一起,当声明data b=a时,就将b的指针指向了a的指针所指向的存储位置,而当将b.key="2"赋值后,其实是将b.key所指向的存储空间赋值"2",这个时候因为a和b的指针是指向同一个存储空间的,所以a.key和b.key的值同时变成了2。
        那么问题出现了,怎么才能使b和a不同时改变呢?有人会告诉我,你可以这样写呀!
    private void  doChange(data a)
      {
       
    data
     b = new data();
       b = a;
       b.key = "2";
       System.Console.WriteLine(b.key.ToString());
       System.Console.WriteLine(a.key.ToString());
      }
    正样,在new的时候,系统会为a和b开辟不同的两个存储空间,这样就不会出现上面的问题了。其实并不是这样的,当你new的时候,确实a和b是有不同的存储位置的,可以当你b=a的时候,其实又是将b的指针指向了a的存储位置上,而将b的存储位置进行了空闲,过不了多久,C#的垃圾回收机制会将b的存储空间进行回收。
        这下岂不坏了,当我么使用一个复杂的对象时候,怎么才能够使一个对象等于另一个对象,而在其中一个对象的属性值改变后,另一个对象的属性不会跟着改变呢?
        在C#中,有写系统对象提供了克隆方法,但是,对于用户自定义的对象是不存在这个方法的,我们要想实现克隆操作,必须手动去便利每一个属性,然后对属性进行赋值,也就是下面的方法。
    private void  doChange(data a)
      {
       
    data
     b = new data();
       b.key = a.key;
       b.key ="2";
       System.Console.WriteLine(b.key.ToString());
       System.Console.WriteLine(a.key.ToString());
      }
    这样对于属性很少的对象操作起来还算可以,但是对于属性很多的对象操作起来却相当麻烦,所以可以采用反射的机制,对每一个属性进行赋值,具体代码如下。
    public static void CopyValue(object origin,object target)
      {
       System.Reflection.PropertyInfo[] properties = (target.GetType()).GetProperties();
       System.Reflection.FieldInfo[] fields = (origin.GetType()).GetFields();
       for ( int i=0; i< fields.Length; i++)
       {
        for ( int j=0; j< properties.Length; j++)
        {
         if (fields[i].Name == properties[j].Name && properties[j].CanWrite)
         {
          properties[j].SetValue(target,fields[i].GetValue(origin),null);
         }
        }
       }
      }
    哈哈,到此为止,问题终于解决了。
     
    借鉴自:http://blog.sina.com.cn/s/blog_4c8a4e5901009lya.html
  • 相关阅读:
    Leetcode Binary Tree Preorder Traversal
    Leetcode Minimum Depth of Binary Tree
    Leetcode 148. Sort List
    Leetcode 61. Rotate List
    Leetcode 86. Partition List
    Leetcode 21. Merge Two Sorted Lists
    Leetcode 143. Reorder List
    J2EE项目应用开发过程中的易错点
    JNDI初认识
    奔腾的代码
  • 原文地址:https://www.cnblogs.com/lijIT/p/4572059.html
Copyright © 2011-2022 走看看