标签:converter uil 跳过 ati generator exce returns 协议 names
由于在实际应用中,需要对大量的对象属性进行复制,原来的方法是通过反射实现,在量大了以后,反射的性能问题就凸显出来了,必须用Emit来实现。
搜了一圈代码,没发现适合的,要么只能在相同类型对象间复制,要么不支持Nullable<T>类型的属性。没办法,自己干吧,一边查资料一边堆IL,终于测试通过。
本类支持在不同类型的对象之间复制属性值,也支持同名但不同类型的属性之间复制,比如从 string 类型复制到 int 类型,从 int 类型复制到 int? 类型。
测试代码如下:
先定义2个不同类型的实体类,他们有同名却不同类型的属性。
public class Obj1 { public string aa { get; set; } public string bb { get; set; } public DateTime? cc { get; set; } public bool? dd { get; set; } public int? ee { get; set; } } public class Obj2 { public string aa { get; set; } public int? bb { get; set; } public DateTime cc { get; set; } public bool? dd { get; set; } public int ee { get; set; } }
测试代码:
Obj1 o1 = new Obj1(); o1.aa = "fdsfds"; o1.bb = "1"; o1.cc = DateTime.Now; o1.dd = true; o1.ee = 3; Obj2 o2 = new Obj2(); o2.aa = "aaa"; o2.dd = true; Obj2 o3 = ObjectCopier.Copy<Obj1, Obj2>(o1, o2);
运行之后,Obj1的属性被完整的复制到Obj2
最后,贴上复制类的源码:
1 /* 2 * 版权及免责申明: 3 * 本程序代码由“程序员海风”开发,并以“BSD协议”对外发布,你无需为使用本程序代码而向作者付费,但请勿删除本段版权说明。 4 * 本程序代码以现状提供,作者不对因使用本程序代码而造成的任何结果负责。 5 * 6 * 作者的BLOG:http://www.cnblogs.com/hhh/ 7 * 作者的PRESS.one:https://press.one/main/p/5475a03ae8011091fc2b98de6d3b181eb9f447df 8 */ 9 using System; 10 using System.Collections.Generic; 11 using System.Collections.Specialized; 12 using System.Linq; 13 using System.Text; 14 using System.Reflection; 15 using System.Reflection.Emit; 16 using System.Collections; 17 18 namespace Haifeng 19 { 20 /// <summary> 21 /// 对象复制器 22 /// </summary> 23 public class ObjectCopier 24 { 25 //把T1转换为T2 26 public delegate T2 ConvertObject<T1, T2>(T1 obj1, T2 obj2); 27 28 //动态方法缓存 29 private static Hashtable caches = new Hashtable(); 30 31 /// <summary> 32 /// 复制对象的属性值到另一个对象 33 /// </summary> 34 /// <param name="sourceObj">原对象</param> 35 /// <param name="targetObj">目标对象</param> 36 public static T2 Copy<T1, T2>(T1 sourceObj, T2 targetObj) 37 { 38 StringCollection sc = new StringCollection(); 39 return Copy<T1, T2>(sourceObj, targetObj, sc); 40 } 41 42 /// <summary> 43 /// 复制对象的属性值到另一个对象 44 /// </summary> 45 /// <param name="sourceObj">原对象</param> 46 /// <param name="targetObj">目标对象</param> 47 /// <param name="ignoreProperties">忽略的属性</param> 48 public static T2 Copy<T1, T2>(T1 sourceObj, T2 targetObj, StringCollection ignoreProperties) 49 { 50 if (sourceObj == null) 51 { 52 throw new ArgumentNullException("sourceObj"); 53 } 54 if (targetObj == null) 55 { 56 throw new ArgumentNullException("targetObj"); 57 } 58 59 ConvertObject<T1, T2> load = GetObjectMethod<T1, T2>(ignoreProperties); 60 return load(sourceObj, targetObj); 61 } 62 63 /// <summary> 64 /// 获取复制T1的属性值到T2的动态方法 65 /// </summary> 66 /// <typeparam name="T1">原对象</typeparam> 67 /// <typeparam name="T2">目标对象</typeparam> 68 /// <param name="ignoreProperties">要跳过的属性名</param> 69 /// <returns></returns> 70 private static ConvertObject<T1, T2> GetObjectMethod<T1, T2>(StringCollection ignoreProperties) 71 { 72 string key = "Convert" + typeof(T1).Name + "To" + typeof(T2).Name; 73 foreach (string str in ignoreProperties) 74 key += str; 75 76 ConvertObject<T1, T2> load = null; 77 if (caches[key] == null) 78 { 79 load = (ConvertObject<T1, T2>)BuildMethod<T1, T2>(ignoreProperties).CreateDelegate(typeof(ConvertObject<T1, T2>)); 80 caches.Add(key, load); 81 } 82 else 83 { 84 load = caches[key] as ConvertObject<T1, T2>; 85 } 86 return load; 87 } 88 89 private static DynamicMethod BuildMethod<T1, T2>(StringCollection ignoreProperties) 90 { 91 Type sourceType = typeof(T1); 92 Type targetType = typeof(T2); 93 string methodName = "Convert" + sourceType.Name + "To" + targetType.Name; 94 foreach (string str in ignoreProperties) 95 methodName += str; 96 97 DynamicMethod method = new DynamicMethod(methodName, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, targetType, 98 new Type[] { sourceType, targetType }, typeof(EntityConverter).Module, true); 99 ILGenerator generator = method.GetILGenerator(); 100 101 //遍历目标对象的属性 102 foreach (PropertyInfo property in targetType.GetProperties()) 103 { 104 //自定义跳过的属性 105 if (ignoreProperties.Contains(property.Name)) 106 continue; 107 //原对象没有相应的属性,跳过 108 MethodInfo getMethod = sourceType.GetMethod("get_" + property.Name); 109 if (getMethod == null) 110 continue; 111 112 generator.Emit(OpCodes.Ldarg_1); // 参数1压栈,参数1是目标对象 113 generator.Emit(OpCodes.Ldarg_0); // 参数0压栈,参数0是原对象 114 generator.Emit(OpCodes.Callvirt, getMethod); //调用 ‘get_属性名‘ 方法,取出属性值 115 116 117 Type sourcePropertyType = sourceType.GetProperty(property.Name).PropertyType; //原对象的属性的类型 118 Type targetPropertyType = property.PropertyType; //目标对象的属性的类型 119 120 //如果类型不一致,需要类型转换 121 if (sourcePropertyType != targetPropertyType) 122 { 123 //支持Nullable<T>类型的属性的复制 124 Type sourcePropertyUnderType = sourcePropertyType; //Nullable<T> 的T的类型 125 Type targetPropertyUnderType = targetPropertyType; //Nullable<T> 的T的类型 126 if (sourcePropertyType.IsGenericType && sourcePropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) 127 sourcePropertyUnderType = Nullable.GetUnderlyingType(sourcePropertyType); 128 if (targetPropertyType.IsGenericType && targetPropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) 129 targetPropertyUnderType = Nullable.GetUnderlyingType(targetPropertyType); 130 131 //如果原始类型是Nullable<T>,需要先取出原始值 132 if (sourcePropertyType.IsGenericType && sourcePropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) 133 { 134 MethodInfo method_temp = sourcePropertyType.GetMethod("get_Value", new Type[] { }); //获取 get_Value 方法 135 var temp = generator.DeclareLocal(sourcePropertyType); //申明一个变量 136 generator.Emit(OpCodes.Stloc, temp); //出栈,存入变量 137 generator.Emit(OpCodes.Ldloca, temp); //压栈,把变量地址压栈 138 generator.Emit(OpCodes.Call, method_temp); //用上面压栈的地址作为对象,调用 get_Value 方法 139 } 140 141 //如果原类型与目标类型不一致,需要转换 142 if (sourcePropertyUnderType != targetPropertyUnderType) 143 { 144 MethodInfo method_temp = GetConverterMethod(targetPropertyUnderType); 145 if (method_temp != null) 146 generator.Emit(OpCodes.Call, method_temp); 147 } 148 149 //如果目标类型是 Nullable<T>,需要转换成Nullable<T> 150 if (targetPropertyType.IsGenericType && targetPropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) 151 { 152 var ctor = targetPropertyType.GetConstructor(new Type[] { targetPropertyUnderType }); //取得Nullable<T>的构造函数方法 153 generator.Emit(OpCodes.Newobj, ctor); //调用构造函数方法,生成 Nullable<T>,参数是上面取出的值 154 } 155 156 } 157 //调用目标对象属性的Set方法,为属性赋值 158 generator.Emit(OpCodes.Callvirt, property.GetSetMethod()); 159 } 160 161 generator.Emit(OpCodes.Ldarg_1); //参数1压栈,参数1是目标对象 162 generator.Emit(OpCodes.Ret); //方法返回 163 return method; 164 } 165 166 167 private static MethodInfo GetConverterMethod(Type type) 168 { 169 switch (type.Name.ToUpper()) 170 { 171 case "INT16": 172 return CreateConverterMethodInfo("ToInt16"); 173 case "INT32": 174 return CreateConverterMethodInfo("ToInt32"); 175 case "INT64": 176 return CreateConverterMethodInfo("ToInt64"); 177 case "SINGLE": 178 return CreateConverterMethodInfo("ToSingle"); 179 case "BOOLEAN": 180 return CreateConverterMethodInfo("ToBoolean"); 181 case "STRING": 182 return CreateConverterMethodInfo("ToString"); 183 case "DATETIME": 184 return CreateConverterMethodInfo("ToDateTime"); 185 case "DECIMAL": 186 return CreateConverterMethodInfo("ToDecimal"); 187 case "DOUBLE": 188 return CreateConverterMethodInfo("ToDouble"); 189 case "GUID": 190 return CreateConverterMethodInfo("ToGuid"); 191 case "BYTE[]": 192 return CreateConverterMethodInfo("ToBytes"); 193 case "BYTE": 194 return CreateConverterMethodInfo("ToByte"); 195 case "NULLABLE`1": 196 { 197 if (type == typeof(DateTime?)) 198 { 199 return CreateConverterMethodInfo("ToDateTimeNull"); 200 } 201 else if (type == typeof(Int32?)) 202 { 203 return CreateConverterMethodInfo("ToInt32Null"); 204 } 205 else if (type == typeof(Boolean?)) 206 { 207 return CreateConverterMethodInfo("ToBooleanNull"); 208 } 209 else if (type == typeof(Int16?)) 210 { 211 return CreateConverterMethodInfo("ToInt16Null"); 212 } 213 else if (type == typeof(Int64?)) 214 { 215 return CreateConverterMethodInfo("ToInt64Null"); 216 } 217 else if (type == typeof(Single?)) 218 { 219 return CreateConverterMethodInfo("ToSingleNull"); 220 } 221 else if (type == typeof(Decimal?)) 222 { 223 return CreateConverterMethodInfo("ToDecimalNull"); 224 } 225 else if (type == typeof(Double?)) 226 { 227 return CreateConverterMethodInfo("ToDoubleNull"); 228 } 229 break; 230 } 231 } 232 return null; 233 } 234 235 private static MethodInfo CreateConverterMethodInfo(string method) 236 { 237 return typeof(MyConverter).GetMethod(method, new Type[] { typeof(object) }); 238 } 239 240 } 241 242 243 public static class MyConverter 244 { 245 public static Int16 ToInt16(object value) 246 { 247 return ChangeType<Int16>(value); 248 } 249 250 public static Int32 ToInt32(object value) 251 { 252 return ChangeType<Int32>(value); 253 } 254 255 public static Int64 ToInt64(object value) 256 { 257 return ChangeType<Int64>(value); 258 } 259 260 public static Single ToSingle(object value) 261 { 262 return ChangeType<Single>(value); 263 } 264 265 public static Boolean ToBoolean(object value) 266 { 267 return ChangeType<Boolean>(value); 268 } 269 270 public static System.String ToString(object value) 271 { 272 return ChangeType<System.String>(value); 273 } 274 275 public static DateTime ToDateTime(object value) 276 { 277 return ChangeType<DateTime>(value); 278 } 279 280 public static Decimal ToDecimal(object value) 281 { 282 return ChangeType<Decimal>(value); 283 } 284 285 public static Double ToDouble(object value) 286 { 287 return ChangeType<Double>(value); 288 } 289 290 public static Guid ToGuid(object value) 291 { 292 return ChangeType<Guid>(value); 293 } 294 295 public static Byte ToByte(object value) 296 { 297 return ChangeType<Byte>(value); 298 } 299 300 public static Byte[] ToBytes(object value) 301 { 302 return ChangeType<Byte[]>(value); 303 } 304 public static DateTime? ToDateTimeNull(object value) 305 { 306 return ChangeType<DateTime?>(value); 307 } 308 309 public static System.Int32? ToInt32Null(object value) 310 { 311 return ChangeType<Int32?>(value); 312 } 313 314 public static Boolean? ToBooleanNull(object value) 315 { 316 return ChangeType<Boolean?>(value); 317 } 318 319 public static Int16? ToInt16Null(object value) 320 { 321 return ChangeType<Int16?>(value); 322 } 323 324 public static Int64? ToInt64Null(object value) 325 { 326 return ChangeType<Int64?>(value); 327 } 328 329 public static Single? ToSingleNull(object value) 330 { 331 return ChangeType<Single?>(value); 332 } 333 334 public static Decimal? ToDecimalNull(object value) 335 { 336 return ChangeType<Decimal?>(value); 337 } 338 339 public static Double? ToDoubleNull(object value) 340 { 341 return ChangeType<Double?>(value); 342 } 343 344 private static T ChangeType<T>(object value) 345 { 346 if (value == null) 347 { 348 return default(T); 349 } 350 351 var t = typeof(T); 352 if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 353 { 354 t = Nullable.GetUnderlyingType(t); ; 355 } 356 357 T ret = default(T); 358 try{ 359 ret = (T)Convert.ChangeType(value, t); 360 } 361 catch { } 362 363 return ret; 364 } 365 } 366 367 }
完。
一个高性能的对象属性复制类,支持不同类型对象间复制,支持Nullable<T>类型属性
标签:converter uil 跳过 ati generator exce returns 协议 names
原文地址:https://www.cnblogs.com/hhh/p/9130779.html