在.net中通常拷贝方法有如下几种:
1.浅拷贝
实现方式:
this.MemberwiseClone();
2.深拷贝
实现方式:
MemoryStream memoryStream = newMemoryStream(); BinaryFormatter formatter = newBinaryFormatter(); formatter.Serialize(memoryStream, this); memoryStream.Position = 0; formatter.Deserialize(memoryStream);
3.另类拷贝:两个对象都已存在,只将其公共数据复制过去
实现方式:利用动态代码的得反射方法,然后将所有公共数据复制
1.DynamicMethodCompiler.cs
using System; using System.Reflection; using System.Reflection.Emit; namespace DynamicCompilationSpike { public delegate object GetHandler(object source); public delegate void SetHandler(object source, object value); public delegate object InstantiateObjectHandler(); public sealed class DynamicMethodCompiler { // DynamicMethodCompiler private DynamicMethodCompiler() { } // CreateInstantiateObjectDelegate internal static InstantiateObjectHandler CreateInstantiateObjectHandler(Type type) { ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null); if (constructorInfo == null) { throw new ApplicationException(string.Format("The type {0} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public).", type)); } DynamicMethod dynamicMethod = new DynamicMethod("InstantiateObject", MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(object), null, type, true); ILGenerator generator = dynamicMethod.GetILGenerator(); generator.Emit(OpCodes.Newobj, constructorInfo); generator.Emit(OpCodes.Ret); return (InstantiateObjectHandler)dynamicMethod.CreateDelegate(typeof(InstantiateObjectHandler)); } // CreateGetDelegate internal static GetHandler CreateGetHandler(Type type, PropertyInfo propertyInfo) { MethodInfo getMethodInfo = propertyInfo.GetGetMethod(true); DynamicMethod dynamicGet = CreateGetDynamicMethod(type); ILGenerator getGenerator = dynamicGet.GetILGenerator(); getGenerator.Emit(OpCodes.Ldarg_0); getGenerator.Emit(OpCodes.Call, getMethodInfo); BoxIfNeeded(getMethodInfo.ReturnType, getGenerator); getGenerator.Emit(OpCodes.Ret); return (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler)); } // CreateGetDelegate internal static GetHandler CreateGetHandler(Type type, FieldInfo fieldInfo) { DynamicMethod dynamicGet = CreateGetDynamicMethod(type); ILGenerator getGenerator = dynamicGet.GetILGenerator(); getGenerator.Emit(OpCodes.Ldarg_0); getGenerator.Emit(OpCodes.Ldfld, fieldInfo); BoxIfNeeded(fieldInfo.FieldType, getGenerator); getGenerator.Emit(OpCodes.Ret); return (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler)); } // CreateSetDelegate internal static SetHandler CreateSetHandler(Type type, PropertyInfo propertyInfo) { MethodInfo setMethodInfo = propertyInfo.GetSetMethod(true); DynamicMethod dynamicSet = CreateSetDynamicMethod(type); ILGenerator setGenerator = dynamicSet.GetILGenerator(); setGenerator.Emit(OpCodes.Ldarg_0); setGenerator.Emit(OpCodes.Ldarg_1); UnboxIfNeeded(setMethodInfo.GetParameters()[0].ParameterType, setGenerator); setGenerator.Emit(OpCodes.Call, setMethodInfo); setGenerator.Emit(OpCodes.Ret); return (SetHandler)dynamicSet.CreateDelegate(typeof(SetHandler)); } // CreateSetDelegate internal static SetHandler CreateSetHandler(Type type, FieldInfo fieldInfo) { DynamicMethod dynamicSet = CreateSetDynamicMethod(type); ILGenerator setGenerator = dynamicSet.GetILGenerator(); setGenerator.Emit(OpCodes.Ldarg_0); setGenerator.Emit(OpCodes.Ldarg_1); UnboxIfNeeded(fieldInfo.FieldType, setGenerator); setGenerator.Emit(OpCodes.Stfld, fieldInfo); setGenerator.Emit(OpCodes.Ret); return (SetHandler)dynamicSet.CreateDelegate(typeof(SetHandler)); } // CreateGetDynamicMethod private static DynamicMethod CreateGetDynamicMethod(Type type) { return new DynamicMethod("DynamicGet", typeof(object), new Type[] { typeof(object) }, type, true); } // CreateSetDynamicMethod private static DynamicMethod CreateSetDynamicMethod(Type type) { return new DynamicMethod("DynamicSet", typeof(void), new Type[] { typeof(object), typeof(object) }, type, true); } // BoxIfNeeded private static void BoxIfNeeded(Type type, ILGenerator generator) { if (type.IsValueType) { generator.Emit(OpCodes.Box, type); } } // UnboxIfNeeded private static void UnboxIfNeeded(Type type, ILGenerator generator) { if (type.IsValueType) { generator.Emit(OpCodes.Unbox_Any, type); } } } }
2.FastClone.cs
using System; using System.Collections.Generic; using System.Text; using System.Reflection; using DynamicCompilationSpike; namespace DynamicCompilationSpike; { public class FastClone { private static Dictionary<Type, FastType> __propertyCache = new Dictionary<Type, FastType>(); /// <summary> /// 添加需要克隆的类型 /// </summary> /// <param name="type"></param> /// <param name="copyPrivate">是否拷贝私有,只读字段数据</param> public static void AddCloneType(Type type,bool copyPrivate) { if (!__propertyCache.ContainsKey(type)) __propertyCache.Add(type, new FastType(type,copyPrivate)); } /// <summary> /// 只克隆对象所有数据 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="src"></param> /// <param name="target"></param> public static void Clone<T>(T src, T target) { FastType fastType = __propertyCache[typeof(T)]; foreach (MemberInfo varMember in fastType.Members) { if (!fastType.Sets.ContainsKey(varMember)) continue; SetHandler setHandler= fastType.Sets[varMember]; if (!fastType.Gets.ContainsKey(varMember)) continue; GetHandler getHandler = fastType.Gets[varMember]; setHandler(target, getHandler(src)); } } } internal class FastType { private Type _type; internal Type Type { get { return _type; } } private Dictionary<MemberInfo, SetHandler> _cacheSets = new Dictionary<MemberInfo, SetHandler>(); public Dictionary<MemberInfo, SetHandler> Sets { get { return _cacheSets; } } private Dictionary<MemberInfo, GetHandler> _cacheGets = new Dictionary<MemberInfo, GetHandler>(); public Dictionary<MemberInfo, GetHandler> Gets { get { return _cacheGets; } } private List<MemberInfo> _cacheMember = new List<MemberInfo>(); public List<MemberInfo> Members { get { return _cacheMember; } } internal FastType(Type type,bool copyPrivate) { _type = type; foreach (PropertyInfo varProperty in type.GetProperties()) { SetHandler setHandler = DynamicMethodCompiler.CreateSetHandler(type, varProperty); GetHandler getHandler = DynamicMethodCompiler.CreateGetHandler(type, varProperty); if (copyPrivate) { _cacheSets.Add(varProperty, setHandler); _cacheGets.Add(varProperty, getHandler); } else { if (varProperty.CanWrite) _cacheSets.Add(varProperty, setHandler); if (varProperty.CanRead) _cacheGets.Add(varProperty, getHandler); } _cacheMember.Add(varProperty); } foreach (FieldInfo varField in type.GetFields()) { SetHandler setHandler = DynamicMethodCompiler.CreateSetHandler(type, varField); GetHandler getHandler = DynamicMethodCompiler.CreateGetHandler(type, varField); if (copyPrivate) { _cacheSets.Add(varField, setHandler); } else { if (!(varField.IsInitOnly || varField.IsLiteral)) _cacheSets.Add(varField, setHandler); } _cacheGets.Add(varField, getHandler); _cacheMember.Add(varField); } } } }
3.program.cs
using System; using System.Collections.Generic; using System.Text; using CodeTimer1; namespace DynamicCompilationSpike { class program { public static void Main() { InfoTest info= new InfoTest("info1"); info.IntValue = 100; info.LongValue = 20000; info.StringValue = "中华人民共和国!"; info.DateTimeValue = DateTime.Now.AddHours(24); info.DecimalValue = 600; InfoTest info2=null; long i= 0; CodeTimer.Time("copy:", 1000000, delegate { info2 = new InfoTest(i.ToString()); i++; info2.IntValue = info.IntValue; info2.LongValue = info.LongValue; info2.StringValue = info.StringValue; info2.DateTimeValue = info.DateTimeValue; info2.DecimalValue = info.DecimalValue; info2.LastName = info.LastName; }); Console.WriteLine(info2); InfoTest info3 = null; FastClone.AddCloneType(typeof(InfoTest),false); i = 0; CodeTimer.Time("clone:", 1000000, delegate { info3= new InfoTest(i.ToString()); i++; FastClone.Clone<InfoTest>(info, info3); }); Console.WriteLine(info3); Console.ReadKey(); } } }
5.性能参数对比