大家都知道,在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);
     }
    }
   }
  }

C#实现拷贝对象的更多相关文章

  1. Python 拷贝对象(深拷贝deepcopy与浅拷贝copy)

    1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. 2. copy.deepcopy 深拷贝 拷贝对象及其子对象 一个很好的例子: # -*-coding:utf-8 -*- ...

  2. 夺命雷公狗—angularjs—23—copy拷贝对象

    copy这在angularjs中是一个拷贝对象的方法: <!DOCTYPE html> <html lang="en" ng-app="myapp&qu ...

  3. 使用copy来拷贝对象

    拷贝对象 您通过将 copy 消息发送给对象,以制作对象的副本. NSArray *myArray = [yourArray copy]; 要拷贝,接收对象的类必须遵守 NSCopying 协议.如果 ...

  4. C++拷贝对象

    简介 对象的创建中,常常有这样的需求,就是把对象复制一份. 而复制有三种方法: 1.通过初始化来复制 例如:Object o1(10); Object o2=o1; 2.通过赋值来复制 例如:Obje ...

  5. Java 使用反射拷贝对象一般字段值

    在<Java解惑>上面看到第八十三例--诵读困难者,要求使用非反射实现单例对象的拷贝.查阅了部分资料,先实现通过反射拷贝对象. 1. 编写需要被拷贝的对象Person package co ...

  6. 读书笔记 effective c++ Item 12 拷贝对象的所有部分

    1.默认构造函数介绍 在设计良好的面向对象系统中,会将对象的内部进行封装,只有两个函数可以拷贝对象:这两个函数分别叫做拷贝构造函数和拷贝赋值运算符.我们把这两个函数统一叫做拷贝函数.从Item5中,我 ...

  7. python中拷贝对象的区别

    一.赋值.引用 在python中赋值语句总是建立对象的引用值,而不是复制对象.因此,python变量更像是指针,而不是数据存储区域 这点和大多数语音类似吧,比如C++.Java等 1.先看个例子: v ...

  8. c# 表达式目录树拷贝对象(根据对象类型动态生成表达式目录树)

    表达式目录树,在C#中用Expression标识,这里就不介绍表达式目录树是什么了,有兴趣可以自行百度搜索,网上资料还是很多的. 这里主要分享的是如何动态构建表达式目录树. 构建表达式目录树的代码挺简 ...

  9. 为什么阿里Java手册推荐慎用 Object 的 clone 方法来拷贝对象

    图片若无法显示,可至掘金查看https://juejin.im/post/5d425230f265da039519d248 前言 在阿里Java开发手册中,有这么一条建议:慎用 Object 的 cl ...

随机推荐

  1. CentOS的KVM实践(虚拟机创建、网桥配置、Spice)

    最近公司准备上一套基于openstack的虚拟桌面系统,作为该项目的负责人,觉得有必要自己实践一下,该系统的搭建.最基础的就是需要了解基于linux的kvm的实践. 一.基础软件包准备 系统是采用px ...

  2. 《JavaScript高级程序设计》读书笔记 ---语句

    do-while语句do-while 语句是一种后测试循环语句,即只有在循环体中的代码执行之后,才会测试出口条件.换句话说,在对条件表达式求值之前,循环体内的代码至少会被执行一次.以下是do-whil ...

  3. InvalidateRect只是增加重绘区域,在下次WM_PAINT的时候才生效

    emWIN里面的无效重绘和windows很类似. WM_InvalidateArea()和WM_InvalidateRect()只重绘指定的区域,其他区域不会重绘,这样避免了闪烁,重绘发生在下次WM_ ...

  4. thinkphp整合系列之phpexcel生成生成excel文件

    在后台管理中会经常需要将数据生成excel表格的: php生成excel有两种方案: 一种是通过phpexcel生成xls格式的表格文件: 另一种则直接通过逗号换行生成csv格式的表格文件: 这里先讲 ...

  5. Linq第三讲

    LINQ 1.查询操作符 (1)源起 .net的设计者在IEnumerable<T>等接口基础之上定义了一系列的扩展方法来方便用户操作集合对象,这些扩展方法构成了LINQ的查询操作符 (2 ...

  6. 触动精灵 alilib

    --gethtml function gethtml (url) local sz = require("sz") local http = require("szock ...

  7. flash 右键菜单隐藏与修改

    来源:http://blog.sina.com.cn/s/blog_7264c84401014fmd.html import flash.ui.ContextMenu;import flash.ui. ...

  8. postgres-xl 集体搭建

    pgxl 集群搭建 一 预备 1 下载安装解压源码 /opt/ curl -O http://files.postgres-xl.org/postgres-xl95r1beta1.tar.gz tar ...

  9. window.open页面关闭后刷新父页面

    如题 function openWin(url,text,winInfo){ var winObj = window.open(url,text,winInfo); var loop = setInt ...

  10. JSP基本语法--包含指令<%@include file="路径"%> <jsp:include page>

    包含指令,真正改变的地方只有具体内容处: 方法1: 在每个jsp页面(HTML)都包含工具栏,头部信息,尾部信息,具体内容 方法2: 将工具栏,头部信息,尾部信息都分成各个独立的文件,使用的时候直接导 ...