用扩展方法来扩展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
}