Base class for cloning an object in C#
来源:互联网 发布:fatego数据包干什么的 编辑:程序博客网 时间:2024/06/05 08:06
Introduction
Although the subject of cloning in the real world is controversial, in the .NET world it is still safe to use, or isn’t it?
How many times did you find yourself implementing the ICloneable
interface for your class, but every time you do the same code, or you do a specific code for each class. And what about, when you add a new field to the class, and you forgot to update the Clone
method for the new field. Believe me, this sort of thing leads to annoying bugs.
This is where my class comes to the rescue. With a little help from the reflection mechanism, I created an abstract class that implements the ICloneable
interface with the default behavior. Now you are probably asking yourself: What is the default behavior? Well I’m glad you asked. Default behavior for cloning, is to clone every field in the class by the following algorithm:
- For each field in the class, ask if it supports the
ICloneable
interface. - If the field doesn’t support the
ICloneable
interface, then the field is set in the regular manner, which means that if this field is a value type, then the value will be copied, but if the field is a reference type, the clone field will be pointing to the same object. - If the field supports the
ICloneable
interface, we use itsClone
method to set it in the clone object. - If the field supports the
IEnumerable
interface, then we need to check if it supports theIList
or theIDictionary
interface. If it does, then we iterate the collection, and for each item in the collection we ask if it supports theICloneable
interface.
How to use
All you have to do to make your class support the ICloneable
interface, is to derive your class from the BaseObject
as follow:
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(); } }}
Now in the Main
method you can do the following:
static void Main(string[] args){ MyContainer con1 = new MyContainer(); MyContainer con2 = (MyContainer)con1.Clone(); con2.myArray[0].id = 5;}
When inspecting the con2
instance you will see that the MyClass
instance in the first index was changed to 5, but the con1
instance remained without changes. So you can see that any field you will add to your class, which support the ICloneable
interface will be cloned as well. Furthermore, if the field supports the IList
interface or the IDictionary
interface, the method will detect it and will loop through all the items and will try to clone them as well.
Implementation
/// <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.
/// The class implements the interface ICloneable and there /// for every object that will be derived
/// 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; }}
- Base class for cloning an object in C#
- Deep Copy in C# (Cloning for a user defined class)
- 转载:C# .NET Tips: Deep Cloning an Object
- A guide to object cloning in java
- Serialization from an Object to XML Document in C#
- node: base class in Laszlo
- Question 30: What is the order of destructor calls for an object of class Y inherited from class X that has an object of class A
- 面向对象关系,type,object,base, class
- Implementing your own base class for user controls in Silverlight 2
- Cloning public code: An example
- How one VBA project can use an object declared in the class module of another project
- can't declare an object without including class header file in MFC vc6
- What’s the behavior when calling an overwritten virtual method in the constructor method of a base class?
- Putting an NSTextView Object in an NSScrollView
- An EventUtility Class for JavaScript
- Creating a Base Window Class in WPF
- [Django] Base class in the model layer
- Class for the use of RegQueryInfoKey pinvoke interop in C#
- Window环境下安装GDAL库的方法
- CMarkup类解析xml文件
- 全面了解setjmp与longjmp(C语言异常处理机制)
- 实践是检验真理的唯一标准
- 一个GDAL的读写数据例子
- Base class for cloning an object in C#
- ERP 在 AIX 的32位操作系统和64位操作系统之间互相迁移
- WIN CE 长按键
- 全面分析Java的垃圾回收机制
- GDAL读取图像文件,建立金字塔
- jBPM开发入门指南(4)
- oracle中的exists 和not exists 用法详解
- 游戏框架
- 很简单的方法找到字符串中不允许的汉字