1 using System; 2 using System.Collections.Generic; 3 using System.Data; 4 using System.Diagnostics; 5 using System.Linq; 6 using System.Linq.Expressions; 7 using System.Reflection; 8 using System.ComponentModel; 9 10 public static class DataReaderExtensions 11 { 12 #region Private Methods 13 private static readonly Dictionary<Type, Delegate> cache = new Dictionary<Type, Delegate>(); 14 private static readonly object cacheLocker = new object(); 15 #endregion 16 17 public static T Field<T>(this IDataReader reader, string name) 18 { 19 return reader[name].ConvertTo<T>(default(T), false); 20 } 21 22 23 public static T Field<T>(this IDataReader reader, int index) 24 { 25 return reader[index].ConvertTo<T>(default(T), false); 26 } 27 28 public static List<T> ToList<T>(this IDataReader reader) where T : class, new() 29 { 30 return Fill<T>(reader, DynamicCreateEntity<T>()).ToList(); 31 } 32 33 public static List<T> ToList<T>(this IDataReader reader, Func<IDataReader, T> predicate) where T : class, new() 34 { 35 return Fill<T>(reader, predicate).ToList(); 36 } 37 38 private static Func<IDataReader, T> DynamicCreateEntity<T>() where T : class, new() 39 { 40 var type = typeof(T); 41 if (cache.ContainsKey(type)) 42 return (Func<IDataReader, T>)cache[type]; 43 lock (cacheLocker) 44 { 45 if (cache.ContainsKey(type)) 46 return (Func<IDataReader, T>)cache[type]; 47 var result = DynamicCreateEntityLogic<T>(); 48 cache.Add(type, result); 49 return result; 50 } 51 } 52 53 private static Func<IDataReader, T> DynamicCreateEntityLogic<T>() where T : class, new() 54 { 55 // Compiles a delegate of the form (IDataReader r) => new T { Prop1 = r.Field<Prop1Type>("Prop1"), ... } 56 ParameterExpression r = Expression.Parameter(typeof(IDataReader), "r"); 57 // Get Properties of the property can read and write 58 var props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanRead && p.CanWrite).ToArray(); 59 // Create property bindings for all writable properties 60 List<MemberBinding> bindings = new List<MemberBinding>(props.Length); 61 // Get the binding method 62 var method = typeof(DataReaderExtensions).GetMethods().First(p => 63 p.Name == "Field" && 64 p.GetParameters().Length == 2 && 65 p.GetParameters()[1].ParameterType == typeof(string)); 66 foreach (PropertyInfo property in (typeof(T).GetProperties())) 67 { 68 // Create expression representing r.Field<property.PropertyType>(property.Name) 69 MethodCallExpression propertyValue = Expression.Call(method.MakeGenericMethod(property.PropertyType), r, Expression.Constant(property.Name)); 70 // Assign the property value to property through a member binding 71 MemberBinding binding = Expression.Bind(property, propertyValue); 72 bindings.Add(binding); 73 } 74 // Create the initializer, which instantiates an instance of T and sets property values 75 // using the member bindings we just created 76 Expression initializer = Expression.MemberInit(Expression.New(typeof(T)), bindings); 77 // Create the lambda expression, which represents the complete delegate (r => initializer) 78 Expression<Func<IDataReader, T>> lambda = Expression.Lambda<Func<IDataReader, T>>(initializer, r); 79 return lambda.Compile(); 80 } 81 82 private static IEnumerable<T> Fill<T>(IDataReader reader, Func<IDataReader, T> predicate) where T : class, new() 83 { 84 while (reader.Read()) 85 yield return predicate(reader); 86 } 87 } 88 89 public static class ExtensionMethod 90 { 91 private static string typeIConvertibleFullName = typeof(IConvertible).FullName; 92 public static T ConvertTo<T>(this object obj, T defaultValue) 93 { 94 if (obj != null) 95 { 96 if (obj is T) 97 return (T)obj; 98 var sourceType = obj.GetType(); 99 var targetType = typeof(T); 100 if (targetType.IsEnum) 101 return (T)Enum.Parse(targetType, obj.ToString(), true); 102 if (sourceType.GetInterface(typeIConvertibleFullName) != null && 103 targetType.GetInterface(typeIConvertibleFullName) != null) 104 return (T)Convert.ChangeType(obj, targetType); 105 var converter = TypeDescriptor.GetConverter(obj); 106 if (converter != null && converter.CanConvertTo(targetType)) 107 return (T)converter.ConvertTo(obj, targetType); 108 converter = TypeDescriptor.GetConverter(targetType); 109 if (converter != null && converter.CanConvertFrom(sourceType)) 110 return (T)converter.ConvertFrom(obj); 111 throw new Exception("convert error."); 112 } 113 throw new ArgumentNullException("obj"); 114 } 115 116 117 public static T ConvertTo<T>(this object obj) 118 { 119 return ConvertTo(obj, default(T)); 120 } 121 122 public static T ConvertTo<T>(this object obj, T defaultValue, bool ignoreException) 123 { 124 if (ignoreException) 125 { 126 try 127 { 128 return obj.ConvertTo<T>(defaultValue); 129 } 130 catch 131 { 132 return defaultValue; 133 } 134 } 135 return obj.ConvertTo<T>(defaultValue); 136 } 137 }
DataReader扩展方法
---------知其然更要知其所以然