用扩展方法来扩展IDataReader接口
实际应用中,有时我们需要用IDataReader来读取数据,或是填充对象,.c# 3.0的扩展方法可以用来扩展这个接口,以实现更方便的功能.以下有泛型方法,也有具体的方法,代码如下:
9 /// <summary> 10 /// Contains extension methods for the IDataReader interface. 11 /// </summary> 12 /// <remark>Author : PetterLiu 2009-04-17 22:34 http://wintersun.cnblogs.com </remark> 13 public static class IDataReaderExtensions 14 { 15 /// <summary> 16 /// Gets the IDataReader value. 17 /// </summary> 18 /// <typeparam name="T"></typeparam> 19 /// <param name="reader">The reader.</param> 20 /// <param name="fieldName">Name of the field.</param> 21 /// <example><code> 22 /// <![CDATA[ 23 /// IDataReader reader = command.ExecuteReader(); 24 /// if (reader.Read()) 25 /// { 26 /// DateTime date = reader.GetValue<DateTime>("CreationDate"); 27 /// Int32? orderId = reader.GetValue<Int32?>("NullableID"); 28 /// } 29 /// ]]> 30 /// </code></example> 31 /// <returns>The column value within the reader typed as T</returns> 32 public static T GetValue<T>(this IDataReader reader, String fieldName) 33 { 34 if (String.IsNullOrEmpty(fieldName)) 35 throw new ArgumentNullException("Field Name cannot be null"); 36 if (reader[fieldName] is DBNull) 37 return default(T); 38 return (T)reader[fieldName]; 39 } 40 41 /// <summary> 42 /// Gets the value or default. 43 /// </summary> 44 /// <typeparam name="T"></typeparam> 45 /// <param name="reader">The reader.</param> 46 /// <param name="columnName">Name of the column.</param> 47 /// <returns>The column value within the reader typed as T.</returns> 48 /// <remark>PetterLiu 2009-04-17 22:34 http://wintersun.cnblogs.com </remark> 49 /// <example><code> 50 /// <![CDATA[ 51 /// int? myInt = reader.GetValueOrDefault<int?>("myColumnName"); 52 /// DateTime myDate = reader.GetValueOrDefault<DateTime>("myColumnName"); 53 /// ]]> 54 /// </code></example> 55 public static T GetValueOrDefault<T>(this IDataReader reader, string columnName) 56 { 57 return GetValueOrDefault<T>(reader, columnName, default(T)); 58 } 59 60 /// <summary> 61 /// Gets the value or default. 62 /// </summary> 63 /// <typeparam name="T"></typeparam> 64 /// <param name="reader">The reader.</param> 65 /// <param name="columnName">Name of the column.</param> 66 /// <param name="defaultValue">The default value.</param> 67 /// <returns>The column value within the reader typed as T.</returns> 68 /// <remark>PetterLiu 2009-04-17 22:34 http://wintersun.cnblogs.com </remark> 69 /// <example><code> 70 /// <![CDATA[ 71 /// //Default to true if myColumnName is null 72 /// bool myBool = reader.GetValueOrDefault<bool>("myColumnName", true); 73 /// ]]> 74 /// </code></example> 75 public static T GetValueOrDefault<T>(this IDataReader reader, string columnName, T defaultValue) 76 { 77 T returnValue = defaultValue; 78 int ordinal; 79 try 80 { 81 ordinal = reader.GetOrdinal(columnName); 82 } 83 catch 84 { 85 throw new Exception(string.Format("Column {0} was not found on IDataReader.", columnName)); 86 } 87 object columnValue = reader.GetValue(ordinal); 88 if (!(columnValue is DBNull)) 89 { 90 Type returnType = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T); 91 returnValue = (T)Convert.ChangeType(columnValue, returnType); 92 } 93 return returnValue; 94 } 95 96 /// <summary> 97 /// This method will return the value of the specified columnIndex, cast to 98 /// the type specified in T. However, if the value found in the reader is 99 /// DBNull, this method will return the default value of the type T. 100 /// </summary> 101 /// <typeparam name="T">The type to which the value found in the reader should be cast.</typeparam> 102 /// <param name="reader">The reader in which columnIndex exists.</param> 103 /// <param name="columnName">The columnIndex to retrieve.</param> 104 /// <returns>The column value within the reader typed as T.</returns> 105 public static T GetValueOrDefault<T>(this IDataReader reader, int columnIndex) 106 { 107 return reader.GetValueOrDefault<T>(reader.GetName(columnIndex)); 108 } 109 110 111 /// <summary> 112 /// Gets the value. 113 /// </summary> 114 /// <typeparam name="T"></typeparam> 115 /// <param name="reader">The reader.</param> 116 /// <param name="field">The field.</param> 117 /// <param name="code">The code.</param> 118 /// <returns>The column value within the reader typed as T.</returns> 119 /// <example><code>address.ID = dr.GetValue("ID", i => dr.GetInt32(i));</code></example> 120 /// <remark>PetterLiu 2009-04-17 22:35 http://wintersun.cnblogs.com </remark> 121 public static T GetValue<T>(this IDataReader reader, string field, Func<int, T> code) 122 { 123 T value = default(T); 124 int ordinal = reader.GetOrdinal(field); 125 if (!reader.IsDBNull(ordinal)) 126 value = code(ordinal); 127 return (value); 128 } 129 130 /// <summary> 131 /// Gets the value or null. 132 /// </summary> 133 /// <typeparam name="T"></typeparam> 134 /// <param name="reader">The reader.</param> 135 /// <param name="field">The field.</param> 136 /// <param name="code">The code.</param> 137 /// <returns>The column value within the reader typed as T.</returns> 138 /// <remark> PetterLiu 2009-04-17 22:38 http://wintersun.cnblogs.com </remark> 139 public static T? GetValueOrNull<T>(this IDataReader reader, string field, Func<int, T> code) where T : struct 140 { 141 T? value = null; 142 int ordinal = reader.GetOrdinal(field); 143 if (!reader.IsDBNull(ordinal)) 144 value = code(ordinal); 145 return (value); 146 } 147 148 149 /// <summary> 150 /// Returns a string if one is present, or null if not 151 /// </summary> 152 /// <param name="reader">The IDbReader to read from</param> 153 /// <param name="index">The index of the column to read from</param> 154 /// <returns>A string, or null if the column's value is NULL</returns> 155 public static string GetNullableString(this IDataRecord reader, int index) 156 { 157 return reader.IsDBNull(index) ? (string)null : reader.GetString(index); 158 } 159 160 /// <summary> 161 /// Returns a bool if one is present, or null if not 162 /// </summary> 163 /// <param name="reader">The IDbReader to read from</param> 164 /// <param name="index">The index of the column to read from</param> 165 /// <returns>A bool, or null if the column's value is NULL</returns> 166 public static bool? GetNullableBool(this IDataRecord reader, int index) 167 { 168 return reader.IsDBNull(index) ? (bool?)null : reader.GetBoolean(index); 169 } 170 171 /// <summary> 172 /// Returns a DateTime if one is present, or null if not 173 /// </summary> 174 /// <param name="reader">The IDbReader to read from</param> 175 /// <param name="index">The index of the column to read from</param> 176 /// <returns>A DateTime, or null if the column's value is NULL</returns> 177 public static DateTime? GetNullableDateTime(this IDataRecord reader, int index) 178 { 179 return reader.IsDBNull(index) ? (DateTime?)null : reader.GetDateTime(index); 180 } 181 182 /// <summary> 183 /// Returns a byte if one is present, or null if not 184 /// </summary> 185 /// <param name="reader">The IDbReader to read from</param> 186 /// <param name="index">The index of the column to read from</param> 187 /// <returns>A byte, or null if the column's value is NULL</returns> 188 public static byte? GetNullableByte(this IDataRecord reader, int index) 189 { 190 return reader.IsDBNull(index) ? (byte?)null : reader.GetByte(index); 191 } 192 193 /// <summary> 194 /// Returns a short if one is present, or null if not 195 /// </summary> 196 /// <param name="reader">The IDbReader to read from</param> 197 /// <param name="index">The index of the column to read from</param> 198 /// <returns>A short, or null if the column's value is NULL</returns> 199 public static short? GetNullableInt16(this IDataRecord reader, int index) 200 { 201 return reader.IsDBNull(index) ? (short?)null : reader.GetInt16(index); 202 } 203 204 /// <summary> 205 /// Returns an int if one is present, or null if not 206 /// </summary> 207 /// <param name="reader">The IDbReader to read from</param> 208 /// <param name="index">The index of the column to read from</param> 209 /// <returns>An int, or null if the column's value is NULL</returns> 210 public static int? GetNullableInt32(this IDataRecord reader, int index) 211 { 212 return reader.IsDBNull(index) ? (int?)null : reader.GetInt32(index); 213 } 214 215 /// <summary> 216 /// Returns a float if one is present, or null if not 217 /// </summary> 218 /// <param name="reader">The IDbReader to read from</param> 219 /// <param name="index">The index of the column to read from</param> 220 /// <returns>A float, or null if the column's value is NULL</returns> 221 public static float? GetNullableFloat(this IDataRecord reader, int index) 222 { 223 return reader.IsDBNull(index) ? (float?)null : reader.GetFloat(index); 224 } 225 226 /// <summary> 227 /// Returns a double if one is present, or null if not 228 /// </summary> 229 /// <param name="reader">The IDbReader to read from</param> 230 /// <param name="index">The index of the column to read from</param> 231 /// <returns>A double, or null if the column's value is NULL</returns> 232 public static double? GetNullableDouble(this IDataRecord reader, int index) 233 { 234 return reader.IsDBNull(index) ? (double?)null : reader.GetDouble(index); 235 } 236 237 }
几个测试的方法,以及另一个测试所用的扩展方法:
12 /// <summary>
13 /// Tests this instance.
14 /// </summary>
15 /// <remark>Author : PetterLiu 2009-04-18 0:07 http://wintersun.cnblogs.com </remark>
16 public void Test()
17 {
18 var x = new Person[]
19 {
20 new Person { Id = 1, Name = "Foo", Age = (int?)null },
21 new Person { Id = 2, Name = "Bar", Age = (int?)10 }
22 };
23 using (var r = x.ToDataReader())
24 {
25 while (r.Read())
26 {
27 Console.WriteLine("{0}\t{1}\t{2}", r.GetInt32(0), r.GetString(1), r.GetNullableInt32(2));
28 Console.WriteLine("{0}\t{1}\t{2}", r.GetInt32(0), r.GetString(1), r.GetValue<int?>("Age"));
29 Console.WriteLine("{0}\t{1}\t{2}", r.GetInt32(0), r.GetString(1), r.GetValue("Age", i => r.GetInt32(i)));
30 }
31 }
32
33 Console.Read();
34 }
35
36 private class Person
37 {
38 public int Id { get; set; }
39 public string Name { get; set; }
40 public int? Age { get; set; }
41 }
62 public static class TestExtenstion
63 {
64 /// <summary>
65 /// Returns an implementation of IDataReader based on the public properties of T,given an IEnumerable<T>
66 /// </summary>
67 /// <typeparam name="T">A type with properties from which to read</typeparam>
68 /// <param name="items">A collection of instances of T</param>
69 /// <returns>An implementation of IDataReader based on the public properties of T</returns>
70 public static IDataReader ToDataReader<T>(this IEnumerable<T> items)
71 {
72 return new DataReader<T>(items);
73 }
74
75
76 /// <summary>
77 /// Private implementation of IDataReader for an IEnumerable<T>
78 /// </summary>
79 /// <typeparam name="T">A type with properties from which to read</typeparam>
80 private class DataReader<T> : IDataReader
81 {
82 public DataReader(IEnumerable<T> items)
83 {
84 _enumerator = items.GetEnumerator();
85
86 foreach (var prop in typeof(T).GetProperties())
87 {
88 _properties[prop.Name] = prop;
89 }
90 }
91
92 private Dictionary<string, PropertyInfo> _properties
93 = new Dictionary<string, PropertyInfo>();
94 private IEnumerator<T> _enumerator;
95
96 #region IDataReader Members
97
98 public void Close()
99 {
100 }
101
102 public int Depth
103 {
104 get { return 0; }
105 }
106
107 public DataTable GetSchemaTable()
108 {
109 throw new NotImplementedException();
110 }
111
112 public bool IsClosed
113 {
114 get { return false; }
115 }
116
117 public bool NextResult()
118 {
119 return false;
120 }
121
122 public bool Read()
123 {
124 return _enumerator.MoveNext();
125 }
126
127 public int RecordsAffected
128 {
129 get { throw new NotImplementedException(); }
130 }
131
132 #endregion
133
134 #region IDisposable Members
135
136 public void Dispose()
137 {
138 }
139
140 #endregion
141
142 #region IDataRecord Members
143
144 public int FieldCount
145 {
146 get { return _properties.Count; }
147 }
148
149 public bool GetBoolean(int i)
150 {
151 return (bool)GetValue(i);
152 }
153
154 public byte GetByte(int i)
155 {
156 return (byte)GetValue(i);
157 }
158
159 public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
160 {
161 throw new NotImplementedException();
162 }
163
164 public char GetChar(int i)
165 {
166 return (char)GetValue(i);
167 }
168
169 public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
170 {
171 throw new NotImplementedException();
172 }
173
174 public IDataReader GetData(int i)
175 {
176 throw new NotImplementedException();
177 }
178
179 public string GetDataTypeName(int i)
180 {
181 var prop = _properties.Values.ToArray()[i];
182 return prop.PropertyType.ToString();
183 }
184
185 public DateTime GetDateTime(int i)
186 {
187 return (DateTime)GetValue(i);
188 }
189
190 public decimal GetDecimal(int i)
191 {
192 return (decimal)GetValue(i);
193 }
194
195 public double GetDouble(int i)
196 {
197 return (double)GetValue(i);
198 }
199
200 public Type GetFieldType(int i)
201 {
202 var prop = _properties.Values.ToArray()[i];
203 return prop.PropertyType;
204 }
205
206 public float GetFloat(int i)
207 {
208 return (float)GetValue(i);
209 }
210
211 public Guid GetGuid(int i)
212 {
213 return (Guid)GetValue(i);
214 }
215
216 public short GetInt16(int i)
217 {
218 return (short)GetValue(i);
219 }
220
221 public int GetInt32(int i)
222 {
223 return (int)GetValue(i);
224 }
225
226 public long GetInt64(int i)
227 {
228 return (long)GetValue(i);
229 }
230
231 public string GetName(int i)
232 {
233 return _properties.Keys.ToArray()[i];
234 }
235
236 public int GetOrdinal(string name)
237 {
238 return _properties.Keys.ToList().IndexOf(name);
239 }
240
241 public string GetString(int i)
242 {
243 return (string)GetValue(i);
244 }
245
246 public object GetValue(int i)
247 {
248 var prop = _properties.Values.ToArray()[i];
249 return prop.GetValue(_enumerator.Current, null);
250 }
251
252 public int GetValues(object[] values)
253 {
254 throw new NotImplementedException();
255 }
256
257 public bool IsDBNull(int i)
258 {
259 var prop = _properties.Values.ToArray()[i];
260 var val = prop.GetValue(_enumerator.Current, null);
261 return (val == null || val == DBNull.Value);
262 }
263
264 public object this[string name]
265 {
266 get
267 {
268 return _properties[name].GetValue(_enumerator.Current,
269 null);
270 }
271 }
272
273 public object this[int i]
274 {
275 get
276 {
277 var prop = _properties.Values.ToArray()[i];
278 return prop.GetValue(_enumerator.Current, null);
279 }
280 }
281
282 #endregion
283 }