第一次寫博客,也不知該寫點什麼好,不如把最近鼓搗的成果分享一下,獨樂樂不如眾樂樂!
Emit,就像個調皮的娃娃,難調教。初時,一個頭兩個大,後面才發現這貨吃硬不吃軟,只能是手寫等效C#代碼,然後模仿生成的IL代碼,雖然過程有點曲折,但娃娃不聽話,終究需要教育引導。
網上關於Emit生成實體的文章也是多數牛毛,亦有如Dapper類的開源框架,重復造輪子,也只是為了知其所以然。我個人還是比較偏向於寫原生SQL,成熟的ORM不在少數,但一碰上由多條件、多表組成的分頁數據,ORM生成的SQL很難盡如人意。直接用DataTable或DataReader可讀性又差,一個個類手寫映射代碼,耗時費力還容易出錯。於是,只能動手弄個轉換器,雖然效率趕不上手寫代碼,但從結果來看,日常使用基本沒啥問題。
DataTable 轉 List 測試結果圖(只測試轉實體消耗的時間,數據量:419,196):
測試代碼:
1、實體類
1 using System; 2 using System.Data; 3 4 namespace Model 5 { 6 public class User2 7 { 8 public string uid { get; set; } 9 10 public string mobile { get; set; } 11 12 public string realname { get; set; } 13 14 public DateTime? regTime { get; set; } 15 16 public string orig_src { get; set; } 17 18 public string referrerid { get; set; } 19 20 public string referrername { get; set; } 21 22 } 23 24 public static class UserFactory 25 { 26 public static User2 GetUser(DataRow dr) 27 { 28 return new User2() 29 { 30 uid = dr[0] as string, 31 mobile = dr[1] as string, 32 realname = dr[2] as string, 33 regTime = (DateTime)dr[3], 34 orig_src = dr[4] as string, 35 referrerid = dr[5] as string, 36 referrername = dr[6] as string 37 }; 38 } 39 } 40 }View Code
2、測試方法
1 static List<Model.User2> DataTableHand(DataTable table) 2 { 3 int rows = null == table ? 0 : table.Rows.Count + 1; 4 if (1 < rows) 5 { 6 try 7 { 8 List<Model.User2> list = new List<Model.User2>(rows); 9 foreach(DataRow row in table.Rows) 10 { 11 list.Add(Model.UserFactory.GetUser(row)); 12 } 13 return list; 14 } 15 catch 16 { 17 } 18 } 19 return null; 20 } 21 22 static void Test() 23 { 24 CodeTimer.Initialize(); 25 // 預熱 26 DataTable tbale1 = db2.GetDataTable("SELECT uid,mobile,realname,regTime, orig_src,referrerid, referrername FROM users LIMIT 1"); 27 var obj6 = MyDataTable<Model.User2>.ToList(tbale1); 28 DataTable table2 = db2.GetDataTable("SELECT uid,mobile,realname,regTime, orig_src,referrerid, referrername FROM users LIMIT 419196"); 29 CodeTimer.Time("手寫:", 1, () => { DataTableHand(table2); }); 30 CodeTimer.Time("Emit:", 1, () => { MyDataTable<Model.User2>.ToList(table2); }); 31 }View Code
相關代碼:
1、MyType.cs
1 namespace Mapper 2 { 3 public class MyType 4 { 5 public static readonly System.Type 6 Nullable = typeof(System.Nullable), 7 Enum = typeof(System.Enum), 8 Object = typeof(object), 9 Byte = typeof(byte), 10 SByte = typeof(sbyte), 11 Int16 = typeof(short), 12 UInt16 = typeof(ushort), 13 Int32 = typeof(int), 14 UInt32 = typeof(uint), 15 Int64 = typeof(long), 16 UInt64 = typeof(ulong), 17 Single = typeof(float), 18 Decimal = typeof(decimal), 19 Double = typeof(double), 20 Boolean = typeof(bool), 21 Char = typeof(char), 22 String = typeof(string), 23 Guid = typeof(System.Guid), 24 DateTime = typeof(System.DateTime), 25 DateTimeOffset = typeof(System.DateTimeOffset), 26 NullableByte = typeof(byte?), 27 NullableSByte = typeof(sbyte?), 28 NullableInt16 = typeof(short?), 29 NullableUInt16 = typeof(ushort?), 30 NullableInt32 = typeof(int?), 31 NullableUInt32 = typeof(uint?), 32 NullableInt64 = typeof(long?), 33 NullableUInt64 = typeof(ulong?), 34 NullableSingle = typeof(float?), 35 NullableDecimal = typeof(decimal?), 36 NullableDouble = typeof(double?), 37 NullableBoolean = typeof(bool?), 38 NullableChar = typeof(char?), 39 NullableGuid = typeof(System.Guid?), 40 NullableDateTime = typeof(System.DateTime?), 41 NullableDateTimeOffset = typeof(System.DateTimeOffset?), 42 ByteArray = typeof(byte[]), 43 IntArray = typeof(int[]), 44 StringArray = typeof(string[]), 45 Exception = typeof(System.Exception), 46 Convert = typeof(System.Convert), 47 IEnumerator = typeof(System.Collections.IEnumerator), 48 MyConvert = typeof(MyConvert), 49 DbColumn = typeof(DbColumnAttribute), 50 DataRow = typeof(System.Data.DataRow), 51 DataRows = typeof(System.Data.DataRowCollection), 52 DataTable = typeof(System.Data.DataTable), 53 DataColumns = typeof(System.Data.DataColumnCollection), 54 IDataRecord = typeof(System.Data.IDataRecord), 55 IDataReader = typeof(System.Data.IDataReader); 56 57 public static readonly System.Type[] 58 ArrayObject = new System.Type[] { Object }, 59 ArrayInt = new System.Type[] { Int32 }, 60 ArrayString = new System.Type[] { String }; 61 } 62 }View Code
2、MyConvert.cs
1 using System; 2 using System.IO; 3 using System.Runtime.Serialization; 4 using System.Runtime.Serialization.Formatters.Binary; 5 6 namespace Mapper 7 { 8 public static class MyConvert 9 { 10 private static readonly IFormatter formatter = new BinaryFormatter(); 11 12 #region 值類型 13 public static bool ToBoolean(object value) 14 { 15 if (value != DBNull.Value) 16 { 17 try 18 { 19 return Convert.ToBoolean(value); 20 } 21 catch 22 { 23 } 24 } 25 return false; 26 } 27 28 public static char ToChar(object value) 29 { 30 if (value != DBNull.Value) 31 { 32 try 33 { 34 string str = Convert.ToString(value); 35 if(null != str && 0 < str.Length) 36 { 37 return str[0]; 38 } 39 } 40 catch 41 { 42 } 43 } 44 return '\0'; 45 } 46 47 public static sbyte ToSByte(object value) 48 { 49 if (value != DBNull.Value) 50 { 51 try 52 { 53 return Convert.ToSByte(value); 54 } 55 catch 56 { 57 } 58 } 59 return 0; 60 } 61 62 public static byte ToByte(object value) 63 { 64 if (value != DBNull.Value) 65 { 66 try 67 { 68 return Convert.ToByte(value); 69 } 70 catch 71 { 72 } 73 } 74 return 0; 75 } 76 77 public static short ToInt16(object value) 78 { 79 if (value != DBNull.Value) 80 { 81 try 82 { 83 return Convert.ToInt16(value); 84 } 85 catch 86 { 87 } 88 } 89 return 0; 90 } 91 92 public static ushort ToUInt16(object value) 93 { 94 if (value != DBNull.Value) 95 { 96 try 97 { 98 return Convert.ToUInt16(value); 99 } 100 catch 101 { 102 } 103 } 104 return 0; 105 } 106 107 public static int ToInt32(object value) 108 { 109 if (value != DBNull.Value) 110 { 111 try 112 { 113 return Convert.ToInt32(value); 114 } 115 catch 116 { 117 } 118 } 119 return 0; 120 } 121 122 public static uint ToUInt32(object value) 123 { 124 if (value != DBNull.Value) 125 { 126 try 127 { 128 return Convert.ToUInt32(value); 129 } 130 catch 131 { 132 } 133 } 134 return 0; 135 } 136 137 public static long ToInt64(object value) 138 { 139 if (value != DBNull.Value) 140 { 141 try 142 { 143 return Convert.ToInt64(value); 144 } 145 catch 146 { 147 } 148 } 149 return 0; 150 } 151 152 public static ulong ToUInt64(object value) 153 { 154 if (value != DBNull.Value) 155 { 156 try 157 { 158 return Convert.ToUInt64(value); 159 } 160 catch 161 { 162 } 163 } 164 return 0; 165 } 166 167 public static float ToSingle(object value) 168 { 169 if (value != DBNull.Value) 170 { 171 try 172 { 173 return Convert.ToSingle(value); 174 } 175 catch 176 { 177 } 178 } 179 return 0f; 180 } 181 182 public static decimal ToDecimal(object value) 183 { 184 if (value != DBNull.Value) 185 { 186 try 187 { 188 return Convert.ToDecimal(value); 189 } 190 catch 191 { 192 } 193 } 194 return 0m; 195 } 196 197 public static double ToDouble(object value) 198 { 199 if (value != DBNull.Value) 200 { 201 try 202 { 203 return Convert.ToDouble(value); 204 } 205 catch 206 { 207 } 208 } 209 return 0d; 210 } 211 212 public static DateTime ToDateTime(object value) 213 { 214 if (value != DBNull.Value) 215 { 216 try 217 { 218 return Convert.ToDateTime(value); 219 } 220 catch 221 { 222 } 223 } 224 return DateTime.MinValue; 225 } 226 227 public static DateTimeOffset ToDateTimeOffset(object value) 228 { 229 if (value != DBNull.Value) 230 { 231 try 232 { 233 return (DateTimeOffset)value; 234 } 235 catch 236 { 237 } 238 } 239 return DateTimeOffset.MinValue; 240 } 241 public static DateTimeOffset? ToDateTimeOffsetNullable(object value) 242 { 243 if (value != DBNull.Value) 244 { 245 try 246 { 247 return (DateTimeOffset)value; 248 } 249 catch 250 { 251 } 252 } 253 return null; 254 } 255 #endregion 256 257 #region 引用類型 258 public static object ToObject(object value) 259 { 260 return value; 261 } 262 263 public static bool? ToBooleanNullable(object value) 264 { 265 if (null != value && value != DBNull.Value) 266 { 267 try 268 { 269 return Convert.ToBoolean(value); 270 } 271 catch 272 { 273 } 274 } 275 return null; 276 } 277 278 public static byte[] ToByteArray(object value) 279 { 280 if (null != value && value != DBNull.Value) 281 { 282 MemoryStream stream = new MemoryStream(); 283 try 284 { 285 formatter.Serialize(stream, value); 286 return stream.GetBuffer(); 287 } 288 finally 289 { 290 stream.Dispose(); 291 } 292 } 293 return null; 294 } 295 296 public static char? ToCharNullable(object value) 297 { 298 if (null != value && value != DBNull.Value) 299 { 300 try 301 { 302 string str = Convert.ToString(value); 303 if (null != str && 0 < str.Length) 304 { 305 return str[0]; 306 } 307 } 308 catch 309 { 310 } 311 } 312 return null; 313 } 314 315 public static Guid ToGuid(object value) 316 { 317 if (null != value && value != DBNull.Value) 318 { 319 try 320 { 321 return (Guid)value; 322 } 323 catch 324 { 325 } 326 } 327 return Guid.Empty; 328 } 329 330 public static byte? ToByteNullable(object value) 331 { 332 if (null != value && value != DBNull.Value) 333 { 334 try 335 { 336 return Convert.ToByte(value); 337 } 338 catch 339 { 340 } 341 } 342 return null; 343 } 344 345 public static sbyte? ToSByteNullable(object value) 346 { 347 if (null != value && value != DBNull.Value) 348 { 349 try 350 { 351 return Convert.ToSByte(value); 352 } 353 catch 354 { 355 } 356 } 357 return null; 358 } 359 360 public static short? ToInt16Nullable(object value) 361 { 362 if (null != value && value != DBNull.Value) 363 { 364 try 365 { 366 return Convert.ToInt16(value); 367 } 368 catch 369 { 370 } 371 } 372 return null; 373 } 374 375 public static ushort? ToUInt16Nullable(object value) 376 { 377 if (null != value && value != DBNull.Value) 378 { 379 try 380 { 381 return Convert.ToUInt16(value); 382 } 383 catch 384 { 385 } 386 } 387 return null; 388 } 389 390 public static int? ToInt32Nullable(object value) 391 { 392 if (null != value && value != DBNull.Value) 393 { 394 try 395 { 396 return Convert.ToInt32(value); 397 } 398 catch 399 { 400 } 401 } 402 return null; 403 } 404 405 public static uint? ToUInt32Nullable(object value) 406 { 407 if (null != value && value != DBNull.Value) 408 { 409 try 410 { 411 return Convert.ToUInt32(value); 412 } 413 catch 414 { 415 } 416 } 417 return null; 418 } 419 420 public static long? ToInt64Nullable(object value) 421 { 422 if (null != value && value != DBNull.Value) 423 { 424 try 425 { 426 return Convert.ToInt64(value); 427 } 428 catch 429 { 430 } 431 } 432 return null; 433 } 434 435 public static ulong? ToUInt64Nullable(object value) 436 { 437 if (null != value && value != DBNull.Value) 438 { 439 try 440 { 441 return Convert.ToUInt64(value); 442 } 443 catch 444 { 445 } 446 } 447 return null; 448 } 449 450 public static float? ToSingleNullable(object value) 451 { 452 if (null != value && value != DBNull.Value) 453 { 454 try 455 { 456 return Convert.ToSingle(value); 457 } 458 catch 459 { 460 } 461 } 462 return null; 463 } 464 465 public static decimal? ToDecimalNullable(object value) 466 { 467 if (null != value && value != DBNull.Value) 468 { 469 try 470 { 471 return Convert.ToDecimal(value); 472 } 473 catch 474 { 475 } 476 } 477 return null; 478 } 479 480 public static double? ToDoubleNullable(object value) 481 { 482 if (null != value && value != DBNull.Value) 483 { 484 try 485 { 486 return Convert.ToDouble(value); 487 } 488 catch 489 { 490 } 491 } 492 return null; 493 } 494 495 public static DateTime? ToDateTimeNullable(object value) 496 { 497 if (null != value && value != DBNull.Value) 498 { 499 try 500 { 501 return Convert.ToDateTime(value); 502 } 503 catch 504 { 505 } 506 } 507 return null; 508 } 509 510 public static Guid? ToGuidNullable(object value) 511 { 512 if (null != value && value != DBNull.Value) 513 { 514 try 515 { 516 return (Guid)value; 517 } 518 catch 519 { 520 } 521 } 522 return null; 523 } 524 #endregion 525 526 #region 其他 527 public static int IndexOf(int length, string[] fields, string name) 528 { 529 for (int index = 0; index < length; index++) 530 { 531 if (string.Equals(fields[index], name, StringComparison.OrdinalIgnoreCase)) 532 { 533 return index; 534 } 535 } 536 return -1; 537 } 538 #endregion 539 540 } 541 }View Code
3、DbColumn.cs
1 using System; 2 using System.Reflection; 3 4 namespace Mapper 5 { 6 public struct DbColumn 7 { 8 public readonly string Name; 9 10 public readonly Type DataType; 11 12 public readonly MethodInfo ConvertMethod; 13 14 public readonly MethodInfo SetMethod; 15 16 public DbColumn(string name, Type type, MethodInfo setMethod, MethodInfo convertMethod) 17 { 18 Name = name; 19 DataType = type; 20 ConvertMethod = convertMethod; 21 SetMethod = setMethod; 22 } 23 } 24 }View Code
4、DbColumnAttribute
1 using System; 2 3 namespace Mapper 4 { 5 public class DbColumnAttribute : Attribute 6 { 7 public DbColumnAttribute() 8 { 9 } 10 11 public string Name { get; set; } 12 } 13 }View Code
5、TypeHelper.cs
1 using System; 2 using System.Reflection; 3 using System.Collections.Generic; 4 5 namespace Mapper 6 { 7 public class TypeHelper 8 { 9 internal static Type GetNullableEnum(Type type) 10 { 11 if (type == MyType.Byte) 12 { 13 return MyType.NullableByte; 14 } 15 16 if (type == MyType.SByte) 17 { 18 return MyType.NullableSByte; 19 } 20 21 if (type == MyType.Int16) 22 { 23 return MyType.NullableInt16; 24 } 25 26 if (type == MyType.Int32) 27 { 28 return MyType.NullableInt32; 29 } 30 31 return MyType.NullableInt32; 32 } 33 34 public static List<DbColumn> GetCanSetColumns(Type type) 35 { 36 Type dataType, tempType; 37 List<DbColumn> result = new List<DbColumn>(); 38 foreach (PropertyInfo prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase)) 39 { 40 MethodInfo setMethod = prop.GetSetMethod(true); 41 if (null == setMethod) 42 { 43 continue; 44 } 45 46 DbColumnAttribute attr = Attribute.GetCustomAttribute(prop, MyType.DbColumn, true) as DbColumnAttribute; 47 if (null == attr) 48 { 49 attr = new DbColumnAttribute(); 50 } 51 52 dataType = prop.PropertyType; 53 if (dataType.IsGenericType) 54 { 55 if (string.Equals(dataType.Name, "Nullable`1")) 56 { 57 tempType = Nullable.GetUnderlyingType(dataType); 58 if (tempType.IsEnum) 59 { 60 dataType = GetNullableEnum(Enum.GetUnderlyingType(tempType)); 61 } 62 } 63 } 64 else if (dataType.IsEnum) 65 { 66 dataType = Enum.GetUnderlyingType(dataType); 67 } 68 69 MethodInfo convertMethod = Method.Get(dataType); 70 if (null != convertMethod) 71 { 72 result.Add(new DbColumn(attr.Name ?? prop.Name, dataType, setMethod, convertMethod)); 73 } 74 } 75 return result; 76 } 77 78 } 79 }View Code
6、Method.cs
1 using System; 2 using System.Reflection; 3 4 namespace Mapper 5 { 6 internal static class Method 7 { 8 9 #region 變量 10 internal static readonly MethodInfo 11 ToObject = MyType.MyConvert.GetMethod("ToObject", MyType.ArrayObject), 12 ToByte = MyType.MyConvert.GetMethod("ToByte", MyType.ArrayObject), 13 ToSByte = MyType.MyConvert.GetMethod("ToSByte", MyType.ArrayObject), 14 ToByteArray = MyType.MyConvert.GetMethod("ToByteArray", MyType.ArrayObject), 15 ToInt16 = MyType.MyConvert.GetMethod("ToInt16", MyType.ArrayObject), 16 ToUInt16 = MyType.MyConvert.GetMethod("ToUInt16", MyType.ArrayObject), 17 ToInt32 = MyType.MyConvert.GetMethod("ToInt32", MyType.ArrayObject), 18 ToUInt32 = MyType.MyConvert.GetMethod("ToUInt32", MyType.ArrayObject), 19 ToInt64 = MyType.MyConvert.GetMethod("ToInt64", MyType.ArrayObject), 20 ToUInt64 = MyType.MyConvert.GetMethod("ToUInt64", MyType.ArrayObject), 21 ToSingle = MyType.MyConvert.GetMethod("ToSingle", MyType.ArrayObject), 22 ToDecimal = MyType.MyConvert.GetMethod("ToDecimal", MyType.ArrayObject), 23 ToDouble = MyType.MyConvert.GetMethod("ToDouble", MyType.ArrayObject), 24 ToBoolean = MyType.MyConvert.GetMethod("ToBoolean", MyType.ArrayObject), 25 ToDateTime = MyType.MyConvert.GetMethod("ToDateTime", MyType.ArrayObject), 26 ToDateTimeOffset = MyType.MyConvert.GetMethod("ToDateTimeOffset", MyType.ArrayObject), 27 ToChar = MyType.MyConvert.GetMethod("ToChar", MyType.ArrayObject), 28 ToStr = MyType.Convert.GetMethod("ToString", MyType.ArrayObject), 29 ToGuid = MyType.MyConvert.GetMethod("ToGuid", MyType.ArrayObject), 30 ToNullableByte = MyType.MyConvert.GetMethod("ToByteNullable", MyType.ArrayObject), 31 ToNullableSByte = MyType.MyConvert.GetMethod("ToSByteNullable", MyType.ArrayObject), 32 ToNullableInt16 = MyType.MyConvert.GetMethod("ToInt16Nullable", MyType.ArrayObject), 33 ToNullableUInt16 = MyType.MyConvert.GetMethod("ToUInt16Nullable", MyType.ArrayObject), 34 ToNullableInt32 = MyType.MyConvert.GetMethod("ToInt32Nullable", MyType.ArrayObject), 35 ToNullableUInt32 = MyType.MyConvert.GetMethod("ToUInt32Nullable", MyType.ArrayObject), 36 ToNullableInt64 = MyType.MyConvert.GetMethod("ToInt64Nullable", MyType.ArrayObject), 37 ToNullableUInt64 = MyType.MyConvert.GetMethod("ToUInt64Nullable", MyType.ArrayObject), 38 ToNullableSingle = MyType.MyConvert.GetMethod("ToSingleNullable", MyType.ArrayObject), 39 ToNullableDecimal = MyType.MyConvert.GetMethod("ToDecimalNullable", MyType.ArrayObject), 40 ToNullableDouble = MyType.MyConvert.GetMethod("ToDoubleNullable", MyType.ArrayObject), 41 ToNullableBoolean = MyType.MyConvert.GetMethod("ToBooleanNullable", MyType.ArrayObject), 42 ToNullableDateTime = MyType.MyConvert.GetMethod("ToDateTimeNullable", MyType.ArrayObject), 43 ToNullableDateTimeOffset = MyType.MyConvert.GetMethod("ToDateTimeOffsetNullable", MyType.ArrayObject), 44 ToNullableChar = MyType.MyConvert.GetMethod("ToCharNullable", MyType.ArrayObject), 45 ToNullableGuid = MyType.MyConvert.GetMethod("ToGuidNullable", MyType.ArrayObject), 46 String_IndexOf = MyType.MyConvert.GetMethod("IndexOf", new Type[] { MyType.Int32, MyType.StringArray, MyType.String }), 47 48 DataReader_Read = MyType.IDataReader.GetMethod("Read"), 49 DataRecord_GetValue = MyType.IDataRecord.GetMethod("GetValue", MyType.ArrayInt), 50 DataRecord_GetName = MyType.IDataRecord.GetMethod("GetName", MyType.ArrayInt), 51 52 DataRow_GetItem = MyType.DataRow.GetMethod("get_Item", MyType.ArrayInt), 53 Rows_GetEnumerator = MyType.DataRows.GetMethod("GetEnumerator"), 54 55 DataColumns_IndexOf = MyType.DataColumns.GetMethod("IndexOf", MyType.ArrayString), 56 DataColumns_Contains = MyType.DataColumns.GetMethod("Contains"), 57 58 DataTable_GetRows = MyType.DataTable.GetMethod("get_Rows"), 59 DataTable_Columns = MyType.DataTable.GetMethod("get_Columns"), 60 61 IEnumerator_MoveNext = MyType.IEnumerator.GetMethod("MoveNext"), 62 IEnumerator_Current = MyType.IEnumerator.GetMethod("get_Current"); 63 #endregion 64 65 #region Get 66 public static MethodInfo Get(Type type) 67 { 68 if(type == MyType.String) 69 { 70 return ToStr; 71 } 72 73 if(type == MyType.Int32) 74 { 75 return ToInt32; 76 } 77 78 if (type == MyType.Int64) 79 { 80 return ToInt64; 81 } 82 83 if(type == MyType.Decimal) 84 { 85 return ToDecimal; 86 } 87 88 if (type == MyType.DateTime) 89 { 90 return ToDateTime; 91 } 92 93 if (type == MyType.NullableDateTime) 94 { 95 return ToNullableDateTime; 96 } 97 98 if(type == MyType.Boolean) 99 { 100 return ToBoolean; 101 } 102 103 if (type == MyType.Double) 104 { 105 return ToDouble; 106 } 107 108 if (type == MyType.Single) 109 { 110 return ToSingle; 111 } 112 113 if(type == MyType.Int16) 114 { 115 return ToInt16; 116 } 117 118 if (type == MyType.UInt16) 119 { 120 return ToUInt16; 121 } 122 123 if (type == MyType.UInt32) 124 { 125 return ToUInt32; 126 } 127 128 if (type == MyType.UInt64) 129 { 130 return ToUInt64; 131 } 132 133 if(type == MyType.Byte) 134 { 135 return ToByte; 136 } 137 138 if (type == MyType.SByte) 139 { 140 return ToSByte; 141 } 142 143 if (type == MyType.ByteArray) 144 { 145 return ToByteArray; 146 } 147 148 if (type == MyType.Char) 149 { 150 return ToChar; 151 } 152 153 if(type == MyType.Guid) 154 { 155 return ToGuid; 156 } 157 158 if(type == MyType.NullableByte) 159 { 160 return ToNullableByte; 161 } 162 if (type == MyType.NullableSByte) 163 { 164 return ToNullableSByte; 165 } 166 167 if(type == MyType.NullableInt16) 168 { 169 return ToNullableInt16; 170 } 171 if (type == MyType.NullableUInt16) 172 { 173 return ToNullableUInt16; 174 } 175 176 if (type == MyType.NullableInt32) 177 { 178 return ToNullableInt32; 179 } 180 if (type == MyType.NullableUInt32) 181 { 182 return ToNullableUInt32; 183 } 184 185 if (type == MyType.NullableInt64) 186 { 187 return ToNullableInt64; 188 } 189 if (type == MyType.NullableUInt64) 190 { 191 return ToNullableUInt64; 192 } 193 194 if(type == MyType.NullableDecimal) 195 { 196 return ToNullableDecimal; 197 } 198 199 if (type == MyType.NullableDouble) 200 { 201 return ToNullableDouble; 202 } 203 204 if (type == MyType.NullableSingle) 205 { 206 return ToNullableSingle; 207 } 208 209 if(type == MyType.NullableBoolean) 210 { 211 return ToNullableBoolean; 212 } 213 214 if (type == MyType.NullableChar) 215 { 216 return ToNullableChar; 217 } 218 219 if (type == MyType.NullableGuid) 220 { 221 return ToNullableGuid; 222 } 223 224 if(type == MyType.DateTimeOffset) 225 { 226 return ToDateTimeOffset; 227 } 228 229 if (type == MyType.NullableDateTimeOffset) 230 { 231 return ToNullableDateTimeOffset; 232 } 233 234 if(type == MyType.Object) 235 { 236 return ToObject; 237 } 238 239 return null; 240 } 241 #endregion 242 } 243 }View Code
7、MyDataReader.cs
1 using System; 2 using System.Data; 3 using System.Reflection; 4 using System.Reflection.Emit; 5 using System.Collections.Generic; 6 using System.Collections.Concurrent; 7 8 namespace Mapper 9 { 10 public class MyDataReader<T> 11 { 12 13 #region 變量 14 15 private delegate T SingleHander(IDataReader dr, int fieldCount); 16 17 private delegate List<T> ListHander(IDataReader dr, int fieldCount); 18 19 private const int MAX_CACHE_COUNT = 10000; 20 21 private static readonly Type 22 typeToSingle = typeof(SingleHander), 23 typeToList = typeof(ListHander); 24 25 private static readonly ConcurrentDictionary<string, SingleHander> 26 dictSingle = new ConcurrentDictionary<string, SingleHander>(StringComparer.OrdinalIgnoreCase); 27 28 private static readonly ConcurrentDictionary<string, ListHander> 29 dictList = new ConcurrentDictionary<string, ListHander>(StringComparer.OrdinalIgnoreCase); 30 31 #endregion 32 33 #region ToList 34 public static List<T> ToList(IDataReader reader) 35 { 36 int cols = null == reader ? 0 : reader.FieldCount; 37 if (0 < cols) 38 { 39 try 40 { 41 Type type = typeof(T); 42 string key = type.FullName; 43 ListHander hander; 44 dictList.TryGetValue(key, out hander); 45 if (null != hander) 46 { 47 return hander(reader, cols); 48 } 49 if (dictList.Count > MAX_CACHE_COUNT) 50 { 51 dictList.Clear(); 52 } 53 hander = GetListHander(type, key); 54 if (null != hander) 55 { 56 return hander(reader, cols); 57 } 58 } 59 catch (Exception ex) 60 { 61 #if DEBUG 62 throw ex; 63 #endif 64 // Log.XXX(ex); 65 } 66 } 67 return null; 68 } 69 70 private static ListHander GetListHander(Type type, string key) 71 { 72 Type typeList = typeof(List<T>); 73 DynamicMethod method = new DynamicMethod(string.Empty, typeList, new Type[] { MyType.IDataReader, MyType.Int32 }, true); 74 ILGenerator il = method.GetILGenerator(); 75 //List<T> list = new List<T>(); 76 il.DeclareLocal(typeList); 77 il.Emit(OpCodes.Newobj, typeList.GetConstructor(Type.EmptyTypes)); 78 il.Emit(OpCodes.Stloc_0); 79 Bind(il, typeList, type); 80 // return list; 81 il.Emit(OpCodes.Ldloc_0); 82 il.Emit(OpCodes.Ret); 83 // set cache 84 ListHander hander = method.CreateDelegate(typeToList) as ListHander; 85 dictList[key] = hander; 86 return hander; 87 } 88 89 private static void Bind(ILGenerator il, Type list, Type item) 90 { 91 if (item.IsValueType) 92 { 93 if (item.IsEnum) 94 { 95 item = Enum.GetUnderlyingType(item); 96 } 97 else if (string.Equals(item.Name, "Nullable`1")) 98 { 99 Type tempType = Nullable.GetUnderlyingType(item); 100 if (tempType.IsEnum) 101 { 102 item = TypeHelper.GetNullableEnum(Enum.GetUnderlyingType(tempType)); 103 } 104 } 105 BindOther(il, item, list.GetMethod("Add")); 106 } 107 else if (item == MyType.String) 108 { 109 BindOther(il, item, list.GetMethod("Add")); 110 } 111 else if (item == MyType.Object) 112 { 113 BindOther(il, item, list.GetMethod("Add"), false); 114 } 115 else 116 { 117 ConstructorInfo constructor = item.GetConstructor(Type.EmptyTypes); 118 if (null != constructor) 119 { 120 BindClass(il, item, list.GetMethod("Add"), constructor); 121 } 122 } 123 } 124 125 private static void BindClass(ILGenerator il,Type type, MethodInfo add, ConstructorInfo constructor) 126 { 127 List<DbColumn> columns = TypeHelper.GetCanSetColumns(type); 128 int count = columns.Count; 129 Label loop = il.DefineLabel(); 130 Label exit = il.DefineLabel(); 131 //T t -> 索引:1 132 il.DeclareLocal(type); 133 // 獲取列索引 134 GetColumnIndices(il, columns, count); 135 // while (dr.Read()) { 136 il.MarkLabel(loop); 137 il.Emit(OpCodes.Ldarg_0); 138 il.Emit(OpCodes.Callvirt, Method.DataReader_Read); 139 il.Emit(OpCodes.Brfalse, exit); 140 BuildItem(il, columns, type, count, constructor); 141 //list.Add(item( 142 il.Emit(OpCodes.Ldloc_0); 143 il.Emit(OpCodes.Ldloc_1); 144 il.Emit(OpCodes.Callvirt, add); 145 // } 146 il.Emit(OpCodes.Br, loop); 147 il.MarkLabel(exit); 148 } 149 150 private static void BindOther(ILGenerator il, Type type, MethodInfo add, bool needConvert = true) 151 { 152 MethodInfo convertMethod = null; 153 if (needConvert) 154 { 155 convertMethod = Method.Get(type); 156 if(null== convertMethod) 157 { 158 return; 159 } 160 } 161 Label loop = il.DefineLabel(); 162 Label exit = il.DefineLabel(); 163 // while (dr.Read()) { 164 il.MarkLabel(loop); 165 il.Emit(OpCodes.Ldarg_0); 166 il.Emit(OpCodes.Callvirt, Method.DataReader_Read); 167 il.Emit(OpCodes.Brfalse, exit); 168 //list.Add(MyConvert.ToXXX(dr.Getvalue(0))); 169 il.Emit(OpCodes.Ldloc_0); 170 il.Emit(OpCodes.Ldarg_0); 171 il.Emit(OpCodes.Ldc_I4_0); 172 il.Emit(OpCodes.Callvirt, Method.DataRecord_GetValue); 173 if (needConvert) 174 { 175 il.Emit(OpCodes.Call, convertMethod); 176 } 177 il.Emit(OpCodes.Callvirt, add); 178 // } 179 il.Emit(OpCodes.Br, loop); 180 il.MarkLabel(exit); 181 } 182 183 private static void GetColumnIndices(ILGenerator il, List<DbColumn> columns, int count) 184 { 185 // int index = 0; 186 il.DeclareLocal(MyType.Int32); 187 il.Emit(OpCodes.Ldc_I4_0); 188 il.Emit(OpCodes.Stloc_2); 189 // string[] fieldNames = new string[fieldCount]; 190 il.DeclareLocal(MyType.StringArray); 191 il.Emit(OpCodes.Ldarg_1); 192 il.Emit(OpCodes.Newarr, MyType.String); 193 il.Emit(OpCodes.Stloc_3); 194 195 Label loop = il.DefineLabel(); 196 // for(; index < count; index++) {fieldNames[i] = IDataRecord.GetName(index);} 197 il.MarkLabel(loop); 198 // fieldNames[index] 199 il.Emit(OpCodes.Ldloc_3); 200 il.Emit(OpCodes.Ldloc_2); 201 202 // = IDataRecord.GetName(index) 203 il.Emit(OpCodes.Ldarg_0); 204 il.Emit(OpCodes.Ldloc_2); 205 il.Emit(OpCodes.Callvirt, Method.DataRecord_GetName); 206 il.Emit(OpCodes.Stelem_Ref); 207 208 // index++; 209 il.Emit(OpCodes.Ldloc_2); 210 il.Emit(OpCodes.Ldc_I4_1); 211 il.Emit(OpCodes.Add); 212 il.Emit(OpCodes.Stloc_2); 213 214 // if(index < fieldCount) { loop 215 il.Emit(OpCodes.Ldloc_2); 216 il.Emit(OpCodes.Ldarg_1); 217 il.Emit(OpCodes.Clt); 218 il.Emit(OpCodes.Brtrue, loop); 219 220 for (int index = 0; index < count; index++) 221 { 222 il.DeclareLocal(MyType.Int32); 223 il.Emit(OpCodes.Ldarg_1); // fieldCount 224 il.Emit(OpCodes.Ldloc_3); // fieldNames 225 il.Emit(OpCodes.Ldstr, columns[index].Name); 226 il.Emit(OpCodes.Call, Method.String_IndexOf); 227 il.Emit(OpCodes.Stloc, index + 4); 228 } 229 } 230 231 private static void BuildItem(ILGenerator il, List<DbColumn> columns, Type type, int count, ConstructorInfo constructor) 232 { 233 il.Emit(OpCodes.Newobj, constructor); 234 il.Emit(OpCodes.Stloc_1); 235 for (int index = 0; index < count; index++) 236 { 237 Label jump = il.DefineLabel(); 238 DbColumn column = columns[index]; 239 // if(index == -1) { => go jump 240 il.Emit(OpCodes.Ldloc, index+4); 241 il.Emit(OpCodes.Ldc_I4_M1); 242 il.Emit(OpCodes.Ceq); 243 il.Emit(OpCodes.Brtrue, jump); 244 // T.xx = MyConvert.ToXXX(dr[index]) 245 il.Emit(OpCodes.Ldloc_1); 246 il.Emit(OpCodes.Ldarg_0); 247 il.Emit(OpCodes.Ldloc, index+4); 248 il.Emit(OpCodes.Callvirt, Method.DataRecord_GetValue); 249 if (column.DataType != MyType.Object) 250 { 251 il.Emit(OpCodes.Call, column.ConvertMethod); 252 } 253 il.Emit(OpCodes.Callvirt, column.SetMethod); 254 // } 255 il.MarkLabel(jump); 256 } 257 } 258 259 #endregion 260 261 #region ToSingle 262 263 public static T ToSingle(IDataReader reader) 264 { 265 int cols = null == reader ? 0 : reader.FieldCount; 266 if (0 < cols) 267 { 268 try 269 { 270 Type type = typeof(T); 271 string key = type.FullName; 272 SingleHander hadner; 273 dictSingle.TryGetValue(key, out hadner); 274 if (null != hadner) 275 { 276 return hadner(reader, cols); 277 } 278 if (dictSingle.Count > MAX_CACHE_COUNT) 279 { 280 dictSingle.Clear(); 281 } 282 hadner = GetSingleHander(type, key); 283 if (null != hadner) 284 { 285 return hadner(reader, cols); 286 } 287 } 288 catch (Exception ex) 289 { 290 #if DEBUG 291 throw ex; 292 #endif 293 // Log.XXX(ex); 294 } 295 } 296 return default(T); 297 } 298 299 private static SingleHander GetSingleHander(Type type, string key) 300 { 301 DynamicMethod method = new DynamicMethod(string.Empty, type, new Type[] { MyType.IDataReader, MyType.Int32 }, true); 302 ILGenerator il = method.GetILGenerator(); 303 Label exit = il.DefineLabel(); 304 // T t 305 il.DeclareLocal(type); 306 // if (reader.Read()) { 307 il.Emit(OpCodes.Ldarg_0); 308 il.Emit(OpCodes.Callvirt, Method.DataReader_Read); 309 il.Emit(OpCodes.Brfalse, exit); 310 Bind(il, type); 311 // } 312 il.MarkLabel(exit); 313 // return 314 il.Emit(OpCodes.Ldloc_0); 315 il.Emit(OpCodes.Ret); 316 SingleHander hander = method.CreateDelegate(typeToSingle) as SingleHander; 317 dictSingle[key] = hander; 318 return hander; 319 } 320 321 private static void Bind(ILGenerator il, Type type) 322 { 323 if (type.IsValueType) 324 { 325 if (type.IsEnum) 326 { 327 type = Enum.GetUnderlyingType(type); 328 } 329 else if (string.Equals(type.Name, "Nullable`1")) 330 { 331 Type tempType = Nullable.GetUnderlyingType(type); 332 if (tempType.IsEnum) 333 { 334 type = TypeHelper.GetNullableEnum(Enum.GetUnderlyingType(tempType)); 335 } 336 } 337 BindOther(il, type); 338 } 339 else if (type == MyType.String) 340 { 341 BindOther(il, type); 342 } 343 else if (type == MyType.Object) 344 { 345 BindOther(il, type, false); 346 } 347 else 348 { 349 ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes); 350 if (null != constructor) 351 { 352 BindClass(il, type, constructor); 353 } 354 } 355 } 356 357 private static void BindOther(ILGenerator il, Type type, bool needConvert = true) 358 { 359 MethodInfo convertMethod = null; 360 if (needConvert) 361 { 362 convertMethod = Method.Get(type); 363 if (null == convertMethod) 364 { 365 return; 366 } 367 } 368 //t = MyConvert.ToXXX(dr.Getvalue(0)); 369 il.Emit(OpCodes.Ldarg_0); 370 il.Emit(OpCodes.Ldc_I4_0); 371 il.Emit(OpCodes.Callvirt, Method.DataRecord_GetValue); 372 if (needConvert) 373 { 374 il.Emit(OpCodes.Call, convertMethod); 375 } 376 il.Emit(OpCodes.Stloc_0); 377 } 378 379 private static void BindClass(ILGenerator il, Type type, ConstructorInfo constructor) 380 { 381 List<DbColumn> columns = TypeHelper.GetCanSetColumns(type); 382 // T item = new T() 383 il.Emit(OpCodes.Newobj, constructor); 384 il.Emit(OpCodes.Stloc_0); 385 386 #region string[] fieldNames = new string[fieldCount] 387 // int index = 0; 變量index索引: 1 388 il.DeclareLocal(MyType.Int32); 389 il.Emit(OpCodes.Ldc_I4_0); 390 il.Emit(OpCodes.Stloc_1); 391 392 // string[] fieldNames = new string[fieldCount]; 索引2 393 il.DeclareLocal(MyType.StringArray); 394 il.Emit(OpCodes.Ldarg_1); 395 il.Emit(OpCodes.Newarr, MyType.String); 396 il.Emit(OpCodes.Stloc_2); 397 398 // for(; index < count; index++) {fieldNames[i] = IDataRecord.GetName(index);} 399 Label loop = il.DefineLabel(); 400 il.MarkLabel(loop); 401 // fieldNames[index] 402 il.Emit(OpCodes.Ldloc_2); 403 il.Emit(OpCodes.Ldloc_1); 404 405 // = IDataRecord.GetName(index) 406 il.Emit(OpCodes.Ldarg_0); 407 il.Emit(OpCodes.Ldloc_1); 408 il.Emit(OpCodes.Callvirt, Method.DataRecord_GetName); 409 il.Emit(OpCodes.Stelem_Ref); 410 411 // index++; 412 il.Emit(OpCodes.Ldloc_1); 413 il.Emit(OpCodes.Ldc_I4_1); 414 il.Emit(OpCodes.Add); 415 il.Emit(OpCodes.Stloc_1); 416 417 // if(index < fieldCount) { loop 418 il.Emit(OpCodes.Ldloc_1); 419 il.Emit(OpCodes.Ldarg_1); 420 il.Emit(OpCodes.Clt); 421 il.Emit(OpCodes.Brtrue, loop); 422 423 #endregion 424 425 #region for (int index = 0; index < count; index++) { item.xx = reader[index] 426 for (int index = 0, count = columns.Count; index < count; index++) 427 { 428 Label jump = il.DefineLabel(); 429 DbColumn column = columns[index]; 430 431 // index = IndexOf(fieldCount, fieldNames, name) 432 il.Emit(OpCodes.Ldarg_1); // fieldCount 433 il.Emit(OpCodes.Ldloc_2); // fieldNames 434 il.Emit(OpCodes.Ldstr, column.Name); 435 il.Emit(OpCodes.Call, Method.String_IndexOf); 436 il.Emit(OpCodes.Stloc_1); 437 438 // if(index == -1) => go jump 439 il.Emit(OpCodes.Ldloc_1); 440 il.Emit(OpCodes.Ldc_I4_M1); 441 il.Emit(OpCodes.Ceq); 442 il.Emit(OpCodes.Brtrue, jump); 443 444 // t.xx = MyConvert.ToXXXX(dr[index]) 445 il.Emit(OpCodes.Ldloc_0); // t 446 il.Emit(OpCodes.Ldarg_0); // reader 447 il.Emit(OpCodes.Ldloc_1); 448 il.Emit(OpCodes.Callvirt, Method.DataRecord_GetValue); 449 if(column.DataType != MyType.Object) 450 { 451 il.Emit(OpCodes.Call, column.ConvertMethod); 452 } 453 il.Emit(OpCodes.Callvirt, column.SetMethod); 454 il.MarkLabel(jump); 455 } 456 457 #endregion 458 } 459 #endregion 460 461 } 462 }View Code
8、MyDataTable.cs
1 using System; 2 using System.Data; 3 using System.Reflection; 4 using System.Reflection.Emit; 5 using System.Collections.Generic; 6 using System.Collections.Concurrent; 7 8 namespace Mapper 9 { 10 public class MyDataTable<T> 11 { 12 13 #region 變量 14 private delegate List<T> ListHander(DataTable table, int rows); 15 16 private delegate T SingleHander(DataTable table); 17 18 private const int MAX_CACHE_COUNT = 10000; 19 20 private static readonly Type 21 typeToSingle = typeof(SingleHander), 22 typeToList = typeof(ListHander); 23 24 private static readonly ConcurrentDictionary<string, SingleHander> 25 dictSingle = new ConcurrentDictionary<string, SingleHander>(StringComparer.OrdinalIgnoreCase); 26 27 private static readonly ConcurrentDictionary<string, ListHander> 28 dictList = new ConcurrentDictionary<string, ListHander>(StringComparer.OrdinalIgnoreCase); 29 #endregion 30 31 #region ToList 32 public static List<T> ToList(DataTable table) 33 { 34 int rows = null == table ? 0 : table.Rows.Count + 1; 35 if (1 < rows) 36 { 37 try 38 { 39 Type type = typeof(T); 40 string key = type.FullName; 41 ListHander hander; 42 dictList.TryGetValue(key, out hander); 43 if (null != hander) 44 { 45 return hander(table, rows); 46 } 47 if (dictList.Count > MAX_CACHE_COUNT) 48 { 49 dictList.Clear(); 50 } 51 hander = GetListHander(type, key); 52 if (null != hander) 53 { 54 return hander(table, rows); 55 } 56 } 57 catch (Exception ex) 58 { 59 #if DEBUG 60 throw ex; 61 #endif 62 // Log.XXX(ex); 63 } 64 } 65 return null; 66 } 67 68 private static ListHander GetListHander(Type type, string key) 69 { 70 Type typeList = typeof(List<T>); 71 DynamicMethod method = new DynamicMethod(string.Empty, typeList, new Type[] { MyType.DataTable, MyType.Int32 }, true); 72 ILGenerator il = method.GetILGenerator(); 73 // List<T> list = new List<T>(rows); 74 il.DeclareLocal(typeList); 75 il.Emit(OpCodes.Ldarg_1); 76 il.Emit(OpCodes.Newobj, typeList.GetConstructor(MyType.ArrayInt)); 77 il.Emit(OpCodes.Stloc_0); 78 Bind(il, typeList, type); 79 // return list 80 il.Emit(OpCodes.Ldloc_0); 81 il.Emit(OpCodes.Ret); 82 ListHander hander = method.CreateDelegate(typeToList) as ListHander; 83 dictList[key] = hander; 84 return hander; 85 } 86 87 private static void Bind(ILGenerator il,Type list, Type item) 88 { 89 if (item.IsValueType) 90 { 91 if (item.IsEnum) 92 { 93 item = Enum.GetUnderlyingType(item); 94 } 95 else if (string.Equals(item.Name, "Nullable`1")) 96 { 97 Type temp = Nullable.GetUnderlyingType(item); 98 if (temp.IsEnum) 99 { 100 item = TypeHelper.GetNullableEnum(Enum.GetUnderlyingType(temp)); 101 } 102 } 103 BindOther(il, item, list.GetMethod("Add")); 104 } 105 else if (item == MyType.String) 106 { 107 BindOther(il, item, list.GetMethod("Add")); 108 } 109 else if (item == MyType.Object) 110 { 111 BindOther(il, item, list.GetMethod("Add"), false); 112 } 113 else 114 { 115 ConstructorInfo constructor = item.GetConstructor(Type.EmptyTypes); 116 if (null != constructor) 117 { 118 BindClass(il, item, list.GetMethod("Add"), constructor); 119 } 120 } 121 } 122 123 private static void BindClass(ILGenerator il, Type type, MethodInfo add, ConstructorInfo constructor) 124 { 125 List<DbColumn> columns = TypeHelper.GetCanSetColumns(type); 126 int count = columns.Count; 127 Label loop = il.DefineLabel(); 128 Label exit = il.DefineLabel(); 129 //T t -> 索引1 130 il.DeclareLocal(type); 131 //IEnumerator enumerator = DataTable.Rows.GetEnumerator(); -> 索引2 132 il.DeclareLocal(MyType.IEnumerator); 133 il.Emit(OpCodes.Ldarg_0); 134 il.Emit(OpCodes.Callvirt, Method.DataTable_GetRows); 135 il.Emit(OpCodes.Callvirt, Method.Rows_GetEnumerator); 136 il.Emit(OpCodes.Stloc_2); 137 // DataRow row; -> 索引3 138 il.DeclareLocal(MyType.DataRow); 139 // 獲取列索引 140 GetColumnIndices(il, columns, count); 141 // while (reader.Read()) { 142 il.MarkLabel(loop); 143 il.Emit(OpCodes.Ldloc_2); 144 il.Emit(OpCodes.Callvirt, Method.IEnumerator_MoveNext); 145 il.Emit(OpCodes.Brfalse, exit); 146 // row = enumerator.Current as DataRow; 147 il.Emit(OpCodes.Ldloc_2); 148 il.Emit(OpCodes.Callvirt, Method.IEnumerator_Current); 149 il.Emit(OpCodes.Castclass, MyType.DataRow); 150 il.Emit(OpCodes.Stloc_3); 151 BuildItem(il, columns, type, count, constructor); 152 // list.Add(t); 153 il.Emit(OpCodes.Ldloc_0); 154 il.Emit(OpCodes.Ldloc_1); 155 il.Emit(OpCodes.Callvirt, add); 156 il.Emit(OpCodes.Br, loop); 157 // } 158 il.MarkLabel(exit); 159 } 160 161 private static void BindOther(ILGenerator il, Type type, MethodInfo add, bool needConvert = true) 162 { 163 MethodInfo convertMethod = null; 164 if (needConvert) 165 { 166 convertMethod = Method.Get(type); 167 if (null == convertMethod) 168 { 169 return; 170 } 171 } 172 Label loop = il.DefineLabel(); 173 Label exit = il.DefineLabel(); 174 //IEnumerator enumerator = DataTable.Rows.GetEnumerator(); -> 索引1 175 il.DeclareLocal(MyType.IEnumerator); 176 il.Emit(OpCodes.Ldarg_0); 177 il.Emit(OpCodes.Callvirt, Method.DataTable_GetRows); 178 il.Emit(OpCodes.Callvirt, Method.Rows_GetEnumerator); 179 il.Emit(OpCodes.Stloc_1); 180 // DataRow row; -> 索引2 181 il.DeclareLocal(MyType.DataRow); 182 // while (enumerator.MoveNext()) { 183 il.MarkLabel(loop); 184 il.Emit(OpCodes.Ldloc_1); 185 il.Emit(OpCodes.Callvirt, Method.IEnumerator_MoveNext); 186 il.Emit(OpCodes.Brfalse, exit); 187 // row = enumerator.Current as DataRow; 188 il.Emit(OpCodes.Ldloc_1); 189 il.Emit(OpCodes.Callvirt, Method.IEnumerator_Current); 190 il.Emit(OpCodes.Castclass, MyType.DataRow); 191 il.Emit(OpCodes.Stloc_2); 192 //list.Add(MyConvert.ToXXX(dr.Getvalue(0))); 193 il.Emit(OpCodes.Ldloc_0); // list 194 il.Emit(OpCodes.Ldloc_2); // row -> DataRow 195 il.Emit(OpCodes.Ldc_I4_0); 196 il.Emit(OpCodes.Callvirt, Method.DataRow_GetItem); 197 if (needConvert) 198 { 199 il.Emit(OpCodes.Call, convertMethod); 200 } 201 il.Emit(OpCodes.Callvirt, add); 202 il.Emit(OpCodes.Br, loop); 203 // } 204 il.MarkLabel(exit); 205 } 206 207 private static void GetColumnIndices(ILGenerator il, List<DbColumn> columns, int count) 208 { 209 // DataColumnCollection colums = DataTable.Columns; -> 索引4 210 il.DeclareLocal(MyType.DataColumns); 211 il.Emit(OpCodes.Ldarg_0); 212 il.Emit(OpCodes.Callvirt, Method.DataTable_Columns); 213 il.Emit(OpCodes.Stloc, 4); 214 for (int index = 0; index < count; index++) 215 { 216 il.DeclareLocal(MyType.Int32); 217 il.Emit(OpCodes.Ldloc, 4); 218 il.Emit(OpCodes.Ldstr, columns[index].Name); 219 il.Emit(OpCodes.Callvirt, Method.DataColumns_IndexOf); 220 il.Emit(OpCodes.Stloc, index+5); 221 } 222 // return result; 223 } 224 225 private static void BuildItem(ILGenerator il, List<DbColumn> columns, Type type, int count, ConstructorInfo constructor) 226 { 227 il.Emit(OpCodes.Newobj, constructor); 228 il.Emit(OpCodes.Stloc_1); 229 for (int index = 0; index < count; index++) 230 { 231 Label next = il.DefineLabel(); 232 DbColumn column = columns[index]; 233 // if(columnIndex == -1) { jump => next 234 il.Emit(OpCodes.Ldloc, index+5); 235 il.Emit(OpCodes.Ldc_I4_M1); 236 il.Emit(OpCodes.Ceq); 237 il.Emit(OpCodes.Brtrue, next); 238 239 // item.xxx = dr[index] 240 il.Emit(OpCodes.Ldloc_1); // t -> T 241 il.Emit(OpCodes.Ldloc, 3); // row -> DataRow 242 il.Emit(OpCodes.Ldloc, index + 5); 243 il.Emit(OpCodes.Callvirt, Method.DataRow_GetItem); 244 if (column.DataType != MyType.Object) 245 { 246 il.Emit(OpCodes.Call, column.ConvertMethod); 247 } 248 il.Emit(OpCodes.Callvirt, column.SetMethod); 249 il.MarkLabel(next); 250 } 251 } 252 #endregion 253 254 #region ToSingle 255 public static T ToSingle(DataTable table) 256 { 257 if (null != table) 258 { 259 try 260 { 261 Type type = typeof(T); 262 string key = type.FullName; 263 SingleHander hander; 264 dictSingle.TryGetValue(key, out hander); 265 if (null != hander) 266 { 267 return hander(table); 268 } 269 if (dictSingle.Count > MAX_CACHE_COUNT) 270 { 271 dictSingle.Clear(); 272 } 273 hander = GetSingleHander(type, key); 274 if (null != hander) 275 { 276 return hander(table); 277 } 278 } 279 catch(Exception ex) 280 { 281 #if DEBUG 282 throw ex; 283 #endif 284 // Log.XXX(ex); 285 } 286 } 287 return default(T); 288 } 289 290 private static SingleHander GetSingleHander(Type type, string key) 291 { 292 DynamicMethod method = new DynamicMethod(string.Empty, type, new Type[] { MyType.DataTable }, true); 293 ILGenerator il = method.GetILGenerator(); 294 Label exit = il.DefineLabel(); 295 // T t 296 il.DeclareLocal(type); 297 // IEnumerator enumerator = DataTable.Rows.GetEnumerator(); 298 il.DeclareLocal(MyType.IEnumerator); 299 il.Emit(OpCodes.Ldarg_0); 300 il.Emit(OpCodes.Callvirt, Method.DataTable_GetRows); 301 il.Emit(OpCodes.Callvirt, Method.Rows_GetEnumerator); 302 il.Emit(OpCodes.Stloc_1); 303 // if (enumerator.MoveNext()) { 304 il.Emit(OpCodes.Ldloc_1); 305 il.Emit(OpCodes.Callvirt, Method.IEnumerator_MoveNext); 306 il.Emit(OpCodes.Brfalse, exit); 307 // DataRow row = enumerator.Current as DataRow; 308 il.DeclareLocal(MyType.DataRow); 309 il.Emit(OpCodes.Ldloc_1); 310 il.Emit(OpCodes.Callvirt, Method.IEnumerator_Current); 311 il.Emit(OpCodes.Castclass, MyType.DataRow); 312 il.Emit(OpCodes.Stloc_2); 313 Bind(il, type); 314 il.MarkLabel(exit); 315 il.Emit(OpCodes.Ldloc_0); 316 il.Emit(OpCodes.Ret); 317 SingleHander hander = method.CreateDelegate(typeToSingle) as SingleHander; 318 dictSingle[key] = hander; 319 return hander; 320 } 321 322 public static void Bind(ILGenerator il, Type type) 323 { 324 if (type.IsValueType) 325 { 326 if (type.IsEnum) 327 { 328 type = Enum.GetUnderlyingType(type); 329 } 330 else if (string.Equals(type.Name, "Nullable`1")) 331 { 332 Type tempType = Nullable.GetUnderlyingType(type); 333 if (tempType.IsEnum) 334 { 335 type = TypeHelper.GetNullableEnum(Enum.GetUnderlyingType(tempType)); 336 } 337 } 338 BindOther(il, type); 339 } 340 else if (type == MyType.String) 341 { 342 BindOther(il, type); 343 } 344 else if (type == MyType.Object) 345 { 346 BindOther(il, type, false); 347 } 348 else 349 { 350 ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes); 351 if (null != constructor) 352 { 353 BindClass(il, type, constructor); 354 } 355 } 356 } 357 358 public static void BindOther(ILGenerator il, Type type, bool needConvert = true) 359 { 360 MethodInfo convertMethod = null; 361 if (needConvert) 362 { 363 convertMethod = Method.Get(type); 364 if (null == convertMethod) 365 { 366 return; 367 } 368 } 369 il.Emit(OpCodes.Ldloc_2); 370 il.Emit(OpCodes.Ldc_I4_0); 371 il.Emit(OpCodes.Call, Method.DataRow_GetItem); 372 if (needConvert) 373 { 374 il.Emit(OpCodes.Call, convertMethod); 375 } 376 il.Emit(OpCodes.Stloc_0); 377 } 378 379 public static void BindClass(ILGenerator il, Type type, ConstructorInfo constructor) 380 { 381 List<DbColumn> columns = TypeHelper.GetCanSetColumns(type); 382 // t = new T() 383 il.Emit(OpCodes.Newobj, constructor); 384 il.Emit(OpCodes.Stloc_0); 385 386 // DataColumnCollection columns = DataTable.Columns; 387 il.DeclareLocal(MyType.DataColumns); 388 il.Emit(OpCodes.Ldarg_0); 389 il.Emit(OpCodes.Callvirt, Method.DataTable_Columns); 390 il.Emit(OpCodes.Stloc_3); 391 392 // int columnIndex; 393 il.DeclareLocal(MyType.Int32); 394 395 for (int index = 0, count = columns.Count; index < count; index++) 396 { 397 Label next = il.DefineLabel(); 398 DbColumn column = columns[index]; 399 // columnIndex = columns.IndexOf(columnName) 400 il.Emit(OpCodes.Ldloc_3); 401 il.Emit(OpCodes.Ldstr, columns[index].Name); 402 il.Emit(OpCodes.Callvirt, Method.DataColumns_IndexOf); 403 il.Emit(OpCodes.Stloc, 4); 404 // if(columnIndex == -1) { jump => next 405 il.Emit(OpCodes.Ldloc, 4); 406 il.Emit(OpCodes.Ldc_I4_M1); 407 il.Emit(OpCodes.Ceq); 408 il.Emit(OpCodes.Brtrue, next); 409 // item.xxx = row[columnIndex] 410 il.Emit(OpCodes.Ldloc_0); 411 il.Emit(OpCodes.Ldloc_2); 412 il.Emit(OpCodes.Ldloc, 4); 413 il.Emit(OpCodes.Callvirt, Method.DataRow_GetItem); 414 if (column.DataType != MyType.Object) 415 { 416 il.Emit(OpCodes.Call, column.ConvertMethod); 417 } 418 il.Emit(OpCodes.Callvirt, column.SetMethod); 419 il.MarkLabel(next); 420 } 421 } 422 #endregion 423 424 } 425 }View Code
很多代碼,也是借鑒廣大網友分享的成果而來,在此表示感謝!