Некоторое время назад я написал кучу методов расширения для DataRow, чтобы сделать именно этот вид уныния ... потому что я ненавижу писать повторяющиеся бесполезные действия. Использование простое:
foreach( DataRow dr in someDataTable )
{
DateTime? dt = dr.CastAsDateTimeNullable( "lastUpdated" ) ;
int id = dr.CastAsInt( "transactionID" ) ;
// etc.
}
Вот часть значений DateTime. Добавление реализации для других типов данных должно быть довольно тривиальным. Не было бы трудно сделать то же самое с DataReader, если бы он был так склонен.
Я пытался придумать обобщенные методы, но ограничения в способе создания обобщений усложняли или делали невозможным выполнение и все равно получали желаемое поведение (например, значения null
вместо default(T)
- получение по умолчанию значения для значений NULL в SQL, которые затруднили бы различие между 0
и null
...).
public static class DataRowExtensions
{
#region downcast to DateTime
public static DateTime CastAsDateTime( this DataRow row , int index )
{
return toDateTime( row[index] ) ;
}
public static DateTime CastAsDateTime( this DataRow row , string columnName )
{
return toDateTime( row[columnName] ) ;
}
public static DateTime? CastAsDateTimeNullable( this DataRow row , int index )
{
return toDateTimeNullable( row[index] );
}
public static DateTime? CastAsDateTimeNullable( this DataRow row , string columnName )
{
return toDateTimeNullable( row[columnName] ) ;
}
#region conversion helpers
private static DateTime toDateTime( object o )
{
DateTime value = (DateTime)o;
return value;
}
private static DateTime? toDateTimeNullable( object o )
{
bool hasValue = !( o is DBNull );
DateTime? value = ( hasValue ? (DateTime?) o : (DateTime?) null ) ;
return value;
}
#endregion
#endregion downcast to DateTime
// ... other implementations elided .. for brevity
}