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
  • 相关阅读:
    抓取登录后的数据
    Form认证的几点说明
    eclipse启动错误:java.lang.NoClassDefFoundError: org/eclipse/core/resources/IContainer
    mysql游标的使用 No data
    mysql insert 主键 重复问题
    tail 命令
    maven 打包可执行jar的方法
    maven中如何打包源代码
    工程师,请优化你的代码
    在服务器端判断request来自Ajax请求(异步)还是传统请求(同步)
  • 原文地址:https://www.cnblogs.com/lijIT/p/4572059.html
Copyright © 2011-2022 走看看