.NET对象克隆的深究 选择自 qwbyxw 的 Blog

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

By Manoj G

Posted 1 Aug 2003

Applied to:

VB.NET, XP, W2K, .NET 1.1, Win9X

摘要:本文讨论了为什么需要对象的克隆,怎样克隆以及对克隆的一些思考。

Download source files - 10 Kb

简介

本文我将讨论.NET编程中一个比较感兴趣的方面——对象克隆。下面将讨论对象克隆的必要性、对象克隆的方法以及关于对象克隆的一些思考。

背景

大家一定知道.NET对象是有二大类型的:  值类型和引用类型。 值类型对象的变量表示对象本身,而且具有“copy-on-assignment”的行为。也就是说, 以下的讨论不适用于值类型。 

另一方面,引用类型的变量实际上是指向堆上的内存。 因此,如果你创建了一个引用类型的变量,并且将一个已存在的对象分配给它,实际上是创建了指向堆上的相同内存的另外一个对象。本文就是讨论这样的情况:创建的一个对象的新的拷贝,并且保存在一个变量中! 

为什么要克隆?

我认为当设置一个对象的状态要付出昂贵的代价,并且又需要取得该对象的一个拷贝以便改变当前的一些状态时,克隆就显得十分必要。下面列举一个刚好能体现我 刚刚所说的情况的例子。 就拿 DataTable 类来说吧。建立一个 DataTable 会包含诸如以下的操作:为取得架构和数据而查询数据库、添加约束、设置主键等等。那么,当需要该 DataTable 的一个新的拷贝,哪怕是对架构作极小的改变或添加新的一行记录等等, 明智的选择会是克隆已存在的对象再对其进行操作,而不是创建一个新的DataTable, 那样将需要更多的时间和资源。 

克隆也广泛应用于数组和集合,这些时候往往会多次需要已存在对象的一个拷贝。 

克隆的类型

我 们基于克隆的程度将克隆分成两大类:“深层”克隆和“浅表”克隆。“浅表”克隆得到一个新的实例,一个与原始对象类型相同、包含值类型字段的拷贝。但是, 如果字段是引用类型的, 该引用将被拷贝, 而不是拷贝引用的对象。 因此,原始对象的引用和克隆对象的引用都指向同一个对象。另一方面, 对象的“深层”克隆包含原始对象直接或间接引用的对象的所有拷贝。下面举例说明。

两种克隆模式的比较

对象X引用对象A,对象A引用对象M。对象X的“浅表”克隆对象Y,同样也引用了对象A。相对比的是,对象X的“深层”克隆对象Y,却直接引用了对象B,并且间接引用对象N,这里,对象B是对象A的拷贝,对象N是对象M的拷贝。

实现克隆

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

.NET定义了一个IClonable接口,一个需要“深层”克隆而不是“浅表”克隆的类必须实现该接口。我们需要提供一个好的实现方法来达到该接口的Clone方法实现的功能。

有 许多方法可以实现“深层”克隆。一个方法是将对象串行化到内存流中,然后反串行化到一个新的对象。我们将使用一个二进制(Binary)的 Formatter类或SOAP formatter类来进行深层串行化。做一个深写成连载长篇而刊登的 formatter 。 这个方法的问题是类和它的成员 (完整的类表) 必须被标记为serializable,否则formatter会发生错误。 

反射是另外一个能达到相同目的的方法。 Amir Harel写的一篇好文章吸引了我, 他使用该方法提供一个好的克隆实现。 这篇文章讨论得非常好! 以下是链接:

http://www.codeproject.com/csharp/cloneimpl_class.asp

上 面讨论的任何一个方法,都要求对象的成员类型能支持自我克隆,以确保“深层”克隆能成功进行。也就是说, 对象必须是可串行化的(serializable) ,或者每个独立的成员必须提供IClonable的实现。 如果不这样,我们根本不可能对对象进行“深层”克隆!

综述

克隆是提供给程序员的一个很好的方法。但是, 我们应该知道什么时候需要提供这样的功能,而且在某些情况下,严格地说,对象不应该提供这一个特性。 SQLTransaction 类为例, 就不支持克隆。这一个类代表了SQL Server数据库的一个事务。 克隆该对象没有任何意义,因为我们可能不能够理解一个数据库的一个活动的事务的克隆! 因此,如果你认为克隆对象的状态会产生应用程序逻辑上的矛盾,就不需要支持克隆。

 

                                                                                           (完)

 

参看原文:An insight into cloning objects in .NET

 

 
C#中实现任意类的完美克隆 简介 虽然在现实世界中的克隆课题是有争议的, 在.NET世界使用它却足够安全, 难道不是吗? 为实现一个类你究竟有多少次要实现ICloneable接口, 而且每一次都写相同的代码,或为每个类写特定的代码。而且,当你的类加入一个新的字段时,往往会忘记更新这个新字段的克隆方法。如果我没说错的话,这种时候往往会带来恼人的bugs。 这是我的类得以存在的原因。 藉由反射机制的小小帮助,我建立了一 阅读详情

相关推荐

C# 对象克隆方法详解

总结起来,C# 的 Clone 方法提供了一种方便的方式来实现对象复制。但需要注意的是,Clone 方法仅仅复制对象的字段和属性的,并不会复制引用类型的成员。类的一个虚拟方法,在 C# 中的各种对象都可以使用该方法进行复制。该方法返回一个新的对象,这个新对象与原始对象具有相同的状态,但是它们是两个独立的实例。从输出结果可以看出,克隆后的对象与原始对象具有相同的属性,但它们是两个独立的实例。,然后使用 Clone 方法复制了这个对象,并将复制后的对象给。方法中,我们创建了一个原始的学生对象

DevGOOD的博客 1876

IClonable接口

实现Clone()方法可以实现深层复制 class test:ICloneable    {        public int a;         #region ICloneable 成员        public object Clone()        {            test t = new test();            t.a = a;     

xxpyeippx的专栏 1258

c# 深度克隆

为了防止list引用类型造成干扰,某些时候需要做深度克隆 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; namespace Common { public c

fuck487的博客 738

浅谈对象的深度拷贝 - IClonable接口

经常我们会发现,当我们把一个对象列表给另一个对象列表之后,一个改变了,另一个也跟着改变了,但是这往往不是我们想看到的那么,怎么办呢?办法只有一个,那就是让你的对象实现IClonable接口对象代码:public class Employee : ICloneable    {        public int EmployeeID { get; set; }        publ...

weixin_34122604的博客 184

详解 c# 克隆

克隆方法是原型设计模式中必须使用的方式,它将返回一个与当前对象数据一致的对象。正如其名,犹如一个模子雕刻而出。克隆类型分为两种:浅克隆、深克隆。 1、浅克隆克隆方式是最简单、最直接的方式。只需要类实现接口ICloneable(在命名空间System.Runtime.InteropServices下)的Clone方法,在方法中使用加入对当前类的MemberwiseClone()方法即可。在浅克隆中,如果原型对象的成员变量是类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复

chinaherolts2008的博客 4236

c# 实体类的克隆复制

实体类直接new对象,是无法克隆出一个同样的类的,只要把新的class改了,就的class也会改变,接下来有两种真正克隆类的办法,基本上可以解决大部分的问题。 1、用反射 Student ss = TransReflection<Student, Student>(stu); private static TOut TransReflection<TIn, TOut>(TIn tIn) { TOut tOu

u014194297的博客 5129

自定义类实现自我克隆

自定义类实现自我克隆 自定义类实现 Cloneable 接口。这是一个标记接口,实现该接口的对象可以实现“自我克隆”,接口里没有定义任何方法。 自定义类实现自己的 clone ()方法。 实现clone()方法时通过 super。clone();调用 Object实现的clone() 方法来得到对象的副本,并返回该副本。 package com.hans.myCl...

依然范特西 538

java“克隆

一起学习java中的"克隆"知识 理解克隆 克隆包括浅克隆与深克隆.克隆就是复制对象时,仅仅复制对象本身(包括对象的基本成员变量),而不复制对象包含的引用指向的对象.克隆不仅复制对象本身,而且复制对象包含的引用指向的所有对象. 自定义类实现克隆 自定义类实现”克隆”的步骤如下: 自定义类实现Cloneable接口.这是一个标记性接口,实现该接口的对象可以实现”自我克隆”,接口里没有定义任...

zcf_hrkj的博客 364

Object类

Object类是所有类、数组、枚举类父类,也就是说,Java允许把任何类型的对象赋给Object类型变量。当定义一个类时没有使用extends关键字为它显式指定父类,则该类默认继承Object父类。因为所有Java类都是Object类的子类,所以任何Java对象都可以调用Object类的方法。Object类提供了如下几个常用方法。 ①boolean equals(Object obj):判断指定对

OR的博客 519

C# 复制克隆认识浅谈

如有雷同,不胜荣欣。若转载,请注明 在C#中,用HashTable,DataTable等复制克隆浅谈,以下直接看样例 HashTable ht = null; ht = new HashTable(); foreach(string s in ht) { //... } //上面遍历的时候须要改动HashTable中的键,通常会报异常,提示您的集合已改动XXX...

weixin_33963594的博客 152

对象引用(浅克隆和深克隆

Javascript中对象的深度克隆 一、js中的数据类型 Js中数据类型分为两大类:(1)基本数据类型:数、字符串、布尔、null、undefined(2)复杂数据类型:对象 二、克隆的概念:        浅度克隆:基本数据类型为传递,对象类型为引用传递        深度克隆:所有属性和方法均完全复制,与原对象完全脱离,也就是说对于

WRITE LESS,DO MORE 514

java 克隆一个对象_java对象克隆

1.浅拷贝可以直接调用Object的clone方法,来完成对象自身的克隆,这个方法只能拷贝各个类的域,如果如果这个类的属性中包含的是一种引用,克隆对象和原对象的相同域会引用同一个引用对象。关于浅拷贝的子对象:原始对象与浅拷贝对象共享的子对象不可变的:不会有任何问题,比如子对象是属于String这样的不可变类型原始对象与浅拷贝共享的子对象可变:参考实现深拷贝2.深拷贝对于每个要拷贝的对象我们需要思...

weixin_35349608的博客 303

疯狂java学习——“深克隆和浅克隆

Java 提供了一个 protected 修饰的 clone()方法,该方法用于帮助其他对象来实现"自我克隆",也就是得到一个当前对象的副本。由于 Object 类提供的clone()方法使用了 protected 修饰,因此该方法只能被子类重写或调用。 自定义类实现"克隆"的步骤如下。 自定义类实现 Cloneable 接口。这是一个标记性的接口,实现该接口的对象可以实现"自我克隆",该接口里没有定义任何方法。 自定义类实现自己的 clone()方法。 实现 clone()方法时通过 **super.c

sinat_40482939的博客 207

.NET对象克隆深究

By Manoj G Posted 1 Aug 2003Applied to:VB.NET, XP, W2K, .NET 1.1, Win9X摘要:本文讨论了为什么需要对象克隆,怎样克隆以及对克隆的一些思考。Download source files - 10 Kb 简介本文我将讨论.NET编程中一个比较感兴趣的方面——对象克隆。下面将讨论对象克隆的必要性、对象

qwbyxw的专栏 1280

【代码笔记】【c#】克隆对象(一般用于实体类)

/// <summary> /// 克隆对象(一般用于实体类) /// </summary> /// <returns></returns> public static void ClassClone<T>(T clzOld, ref T clzNew) ...

Amy安的博客 847

java之克隆一个对象(此对象包含list引用)-clone()

在java克隆的时候,所要克隆对象包含比较复杂的数据结构如:list集合等一些复杂的引用的时候,该怎么克隆。 深克隆,浅克隆的实现和理解。

请叫我大师兄 1万+

java自我复制_Java中的深拷贝(深复制)和浅拷贝(浅复制)

深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java。虽然java自动管理对象的回收,但对于深拷贝(深复制)和浅拷贝(浅复制),我们还是要给予足够的重视,因为有时这两个概念往往会给我们带来不小的困惑。浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。深拷贝不...

weixin_39699121的博客 248

对象克隆

对象克隆 java当中的克隆跟生物上所说的克隆类似,就是复制出一个一模一样的个体,当然迁移到java当中,那就是复制出一个一模一样对象,别忘了java当中有句话叫做一切皆对象。通过克隆就能提高对象的独立性,使用起来更加方便,也更安全。 克隆作用 克隆的分类 图片链接和图片上传 LaTex数学公式 克隆的作用 对象克隆主要是为了解决引用类型在进行等号赋时使得两个引用同时指向同一个...

一个人的编程之路 1000
上一篇: 解决排列组合问题的通用算法
下一篇: C# 序列化技术
comeon_data
博客等级 码龄22年 15粉丝 63原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值