第一次寫博客,也不知該寫點什麼好,不如把最近鼓搗的成果分享一下,獨樂樂不如眾樂樂!
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
很多代碼,也是借鑒廣大網友分享的成果而來,在此表示感謝!