当前位置: 首页 > news >正文

使用IL实现对象的Clone,浅拷贝,和深拷贝的几篇文章

对于实现任意对象的Clone,以前也看到过不少讨论 的文章和实现。暂时先发到首页,供大家讨论,如果觉得不合适我会拆下

以下是Whizzo's 的两篇文章:
Object Cloning Using IL in C# 
            这篇文章作者分别用IL,反射实现了浅拷贝,并对普通的clone、IL、反射这三种实现方式做性能的对比


Object Deep Cloning using IL in C# - version 1.0 
            这篇文章作者分别用IL,反射实现了浅拷贝和深拷贝,并对普通的clone、IL深拷贝、IL浅拷贝、反射这三种实现方式做性能的对比,
            目前只支持Colone的对象具有默认构造函数的对象。

Code
using System;
using System.Collections.Generic;
using System.Text;

namespace Cloning
{
   
public class Person
   
{
       
private int _id;
       
private string _name;
       
private string _firstName;
       
private string _field1, _field2, _field3;

       
public Person()
       
{
           
this.Addresses = new List<Address>();
        }


       
public int ID
       
{
           
get { return _id; }
           
set { _id = value; }
        }


       
public string Name
       
{
           
get { return _name; }
           
set { _name = value; }
        }


       
public string FirstName
       
{
           
get { return _firstName; }
           
set { _firstName = value; }
        }


       
private Address _address;

       
public Address Address
       
{
           
get { return _address; }
           
set { _address = value; }
        }


       
private List<Address> _addresses;

       
public List<Address> Addresses
       
{
           
get { return _addresses; }
           
set { _addresses = value; }
        }


    }


   
public class Address
   
{
       
public Address()
       
{
           
this.AddressID = -1;
        }


       
public Address(int aid)
       
{
           
this.AddressID = aid;
        }


       
private int _addressID;

       
public int AddressID
       
{
           
get { return _addressID; }
           
set { _addressID = value; }
        }


       
private string _street;

       
public string Street
       
{
           
get { return _street; }
           
set { _street = value; }
        }


       
private string _city;

       
public string City
       
{
           
get { return _city; }
           
set { _city = value; }
        }


    }

}



Clone类
Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
using System.Collections;

namespace Cloning
{
   
/**//// <summary>   
   
/// Delegate handler that's used to compile the IL to.   
   
/// (This delegate is standard in .net 3.5)   
   
/// </summary>   
   
/// <typeparam name="T1">Parameter Type</typeparam>   
   
/// <typeparam name="TResult">Return Type</typeparam>   
   
/// <param name="arg1">Argument</param>   
   
/// <returns>Result</returns>   

    public delegate TResult Func<T1, TResult>(T1 arg1);

   
public class Cloning
   
{
       
/**//// <summary>   
       
/// This dictionary caches the delegates for each 'to-clone' type.   
       
/// </summary>   

        private static Dictionary<Type, Delegate> _cachedIL = new Dictionary<Type, Delegate>();
       
private static Dictionary<Type, Delegate> _cachedILDeep = new Dictionary<Type, Delegate>();
       
private LocalBuilder _lbfTemp;

       
/**//// <summary>   
       
/// Clone one person object with reflection   
       
/// </summary>   
       
/// <param name="p">Person to clone</param>   
       
/// <returns>Cloned person</returns>   

        public static Person CloneObjectWithReflection(Person p)
       
{
            FieldInfo[] fis
= p.GetType().GetFields(System.Reflection.BindingFlags.Instance |
                System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic);
            Person newPerson
= new Person();
           
foreach (FieldInfo fi in fis)
           
{
                fi.SetValue(newPerson, fi.GetValue(p));
            }

           
return newPerson;
        }


       
/**//// <summary>   
       
/// Clone a person object by manually typing the copy statements.   
       
/// </summary>   
       
/// <param name="p">Object to clone</param>   
       
/// <returns>Cloned object</returns>   

        public static Person CloneNormal(Person p)
       
{
            Person newPerson
= new Person();
            newPerson.ID
= p.ID;
            newPerson.Name
= p.Name;
            newPerson.FirstName
= p.FirstName;
            newPerson.Address
= new Address();
            newPerson.Address.AddressID
= p.Address.AddressID;
            newPerson.Address.City
= p.Address.City;
            newPerson.Address.Street
= p.Address.Street;
           
if(newPerson.Addresses!=null)
           
{
                newPerson.Addresses
= new List<Address>();
               
foreach (Address a in newPerson.Addresses)
               
{
                    newPerson.Addresses.Add(a);
                }

            }

           
return newPerson;
        }


       
/**//// <summary>   
       
/// Generic cloning method that clones an object using IL.   
       
/// Only the first call of a certain type will hold back performance.   
       
/// After the first call, the compiled IL is executed.   
       
/// </summary>   
       
/// <typeparam name="T">Type of object to clone</typeparam>   
       
/// <param name="myObject">Object to clone</param>   
       
/// <returns>Cloned object</returns>   

        public static T CloneObjectWithILShallow<T>(T myObject)
       
{
            Delegate myExec
= null;
           
if (!_cachedIL.TryGetValue(typeof(T), out myExec))
           
{
               
// Create ILGenerator (both DM declarations work)
               
// DynamicMethod dymMethod = new DynamicMethod("DoClone", typeof(T),
               
//      new Type[] { typeof(T) }, true);
                DynamicMethod dymMethod = new DynamicMethod("DoClone", typeof(T),
                   
new Type[] { typeof(T) }, Assembly.GetExecutingAssembly().ManifestModule, true);
                ConstructorInfo cInfo
= myObject.GetType().GetConstructor(new Type[] { });
                ILGenerator generator
= dymMethod.GetILGenerator();
                LocalBuilder lbf
= generator.DeclareLocal(typeof(T));
                generator.Emit(OpCodes.Newobj, cInfo);
                generator.Emit(OpCodes.Stloc_0);
               
foreach (FieldInfo field in myObject.GetType().GetFields(
                        System.Reflection.BindingFlags.Instance
                       
| System.Reflection.BindingFlags.NonPublic
                       
| System.Reflection.BindingFlags.Public))
               
{
                    generator.Emit(OpCodes.Ldloc_0);
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldfld, field);
                    generator.Emit(OpCodes.Stfld, field);
                }

                generator.Emit(OpCodes.Ldloc_0);
                generator.Emit(OpCodes.Ret);
                myExec
= dymMethod.CreateDelegate(typeof(Func<T, T>));
                _cachedIL.Add(
typeof(T), myExec);
            }

           
return ((Func<T, T>)myExec)(myObject);
        }


       
public T CloneObjectWithILDeep<T>(T myObject)
       
{
            Delegate myExec
= null;
           
if (!_cachedILDeep.TryGetValue(typeof(T), out myExec))
           
{
               
// Create ILGenerator (both DM declarations work)
               
// DynamicMethod dymMethod = new DynamicMethod("DoClone", typeof(T),
               
//      new Type[] { typeof(T) }, true);
                DynamicMethod dymMethod = new DynamicMethod("DoClone", typeof(T),
                   
new Type[] { typeof(T) }, Assembly.GetExecutingAssembly().ManifestModule, true);
                ConstructorInfo cInfo
= myObject.GetType().GetConstructor(new Type[] { });
                ILGenerator generator
= dymMethod.GetILGenerator();
                LocalBuilder lbf
= generator.DeclareLocal(typeof(T));
                generator.Emit(OpCodes.Newobj, cInfo);
                generator.Emit(OpCodes.Stloc_0);

               
foreach (FieldInfo field in typeof(T).GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public))
               
{
                   
if (field.FieldType.IsValueType || field.FieldType == typeof(string))
                        CopyValueType(generator, field);
                   
else if (field.FieldType.IsClass)
                        CopyReferenceType(generator, field);
                }

                generator.Emit(OpCodes.Ldloc_0);
                generator.Emit(OpCodes.Ret);
                myExec
= dymMethod.CreateDelegate(typeof(Func<T, T>));
                _cachedILDeep.Add(
typeof(T), myExec);
            }

           
return ((Func<T, T>)myExec)(myObject);
        }


       
private void CreateNewTempObject(ILGenerator generator, Type type)
       
{
            ConstructorInfo cInfo
= type.GetConstructor(new Type[] { });
            generator.Emit(OpCodes.Newobj, cInfo);
            generator.Emit(OpCodes.Stloc, _lbfTemp);
        }


       
private void CopyValueType(ILGenerator generator, FieldInfo field)
       
{
            generator.Emit(OpCodes.Ldloc_0);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, field);
            generator.Emit(OpCodes.Stfld, field);
        }


       
private void CopyValueTypeTemp(ILGenerator generator, FieldInfo fieldParent, FieldInfo fieldDetail)
       
{
            generator.Emit(OpCodes.Ldloc_1);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldfld, fieldParent);
            generator.Emit(OpCodes.Ldfld, fieldDetail);
            generator.Emit(OpCodes.Stfld, fieldDetail);
        }


       
private void PlaceNewTempObjInClone(ILGenerator generator, FieldInfo field)
       
{
           
// Get object from custom location and store it in right field of location 0
            generator.Emit(OpCodes.Ldloc_0);
            generator.Emit(OpCodes.Ldloc, _lbfTemp);
            generator.Emit(OpCodes.Stfld, field);
        }


       
private void CopyReferenceType(ILGenerator generator, FieldInfo field)
       
{
           
// We have a reference type.
            _lbfTemp = generator.DeclareLocal(field.FieldType);
           
if (field.FieldType.GetInterface("IEnumerable") != null)
           
{
               
// We have a list type (generic).
                if (field.FieldType.IsGenericType)
               
{
                   
// Get argument of list type
                    Type argType = field.FieldType.GetGenericArguments()[0];
                   
// Check that it has a constructor that accepts another IEnumerable.
                    Type genericType = Type.GetType("System.Collections.Generic.IEnumerable`1[" 
                           
+ argType.FullName + "]");
                   
                    ConstructorInfo ci
= field.FieldType.GetConstructor(new Type[] { genericType });
                   
if (ci != null)
                   
{
                       
// It has! (Like the List<> class)
                        generator.Emit(OpCodes.Ldarg_0);
                        generator.Emit(OpCodes.Ldfld, field);
                        generator.Emit(OpCodes.Newobj, ci);
                        generator.Emit(OpCodes.Stloc, _lbfTemp);
                        PlaceNewTempObjInClone(generator, field);
                    }

                }

            }

           
else
           
{
                CreateNewTempObject(generator, field.FieldType);
                PlaceNewTempObjInClone(generator, field);
               
foreach (FieldInfo fi in field.FieldType.GetFields(System.Reflection.BindingFlags.Instance
                   
| System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public))
               
{
                   
if (fi.FieldType.IsValueType || fi.FieldType == typeof(string))
                        CopyValueTypeTemp(generator, field, fi);
                   
else if (fi.FieldType.IsClass)
                        CopyReferenceType(generator, fi);
                }

            }

        }


    }

}



测试程序:
namespace Cloning
{
   
class Program
   
{
       
static void Main(string[] args)
       
{
           
// Do some cloning tests
            Cloning.TestCloning tc = new Cloning.TestCloning();
            tc.DoTest();
        }

    }

}

 

还有一篇:Rick Minerich - A .NET Assembly for Cloning Objects with Arbitrary Field Value Changes: IcManipluator

Update 2008-12-26:

Object Deep Cloning using IL in C# - version 1.1

 

转载于:https://www.cnblogs.com/jintan/archive/2008/07/13/1241908.html

相关文章:

  • 基于 JavaScript 的操作系统你听说过吗?
  • JQuery 日程管理组件 FullCalendar 文档
  • 索引
  • 黄东旭:When TiDB Meets Kubernetes
  • c# FileSystemWatcher控件的使用方法
  • Android 自己定义View学习(2)
  • redis订阅/发布 分享
  • 红与黑
  • 读取Web.Config中的设置参数之二
  • 自学有感7
  • Http之Get/Post请求区别
  • 清河好程序猿训练营是什么?
  • 分享:Ajax工具文件
  • 洛谷P1287 盒子与球 数学
  • 识别地图上的地名-- 笔记一
  • 【刷算法】求1+2+3+...+n
  • AngularJS指令开发(1)——参数详解
  • canvas 五子棋游戏
  • classpath对获取配置文件的影响
  • iOS | NSProxy
  • JAVA SE 6 GC调优笔记
  • nodejs实现webservice问题总结
  • Python_网络编程
  • React Native移动开发实战-3-实现页面间的数据传递
  • spring cloud gateway 源码解析(4)跨域问题处理
  • Vue.js源码(2):初探List Rendering
  • vue-router的history模式发布配置
  • 对JS继承的一点思考
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 来,膜拜下android roadmap,强大的执行力
  • 如何解决微信端直接跳WAP端
  • 深入 Nginx 之配置篇
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 交换综合实验一
  • 我们雇佣了一只大猴子...
  • #、%和$符号在OGNL表达式中经常出现
  • #QT(一种朴素的计算器实现方法)
  • #微信小程序(布局、渲染层基础知识)
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • (1)(1.19) TeraRanger One/EVO测距仪
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (23)Linux的软硬连接
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (十六)Flask之蓝图
  • (一)Linux+Windows下安装ffmpeg
  • (转)linux下的时间函数使用
  • (转载)深入super,看Python如何解决钻石继承难题
  • ***检测工具之RKHunter AIDE
  • .NET(C#、VB)APP开发——Smobiler平台控件介绍:Bluetooth组件
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • .NET6 开发一个检查某些状态持续多长时间的类
  • .netcore 如何获取系统中所有session_ASP.NET Core如何解决分布式Session一致性问题
  • .net反编译的九款神器
  • @RequestParam,@RequestBody和@PathVariable 区别
  • [Android] 修改设备访问权限