Part of the data layer for my application is a converter cache similar to System.Data.DataRowExtensions.UnboxT
, used in Linq-to-Data. The premise of the cache for all known types I generate a simple converter and cache it. The converter casts the object as T, or in the case of DBNull.Value
, returns default(T)
(unlike UnboxT
which throws an exception on non-nullable value types.) The reason I can't use UnboxT is that our developers don't like checking for DBNull before assigning a value from the datarow and they just want it done for them.
We also have a factory to generate helper delegate that instantiates objects off of a DataRow, and it'd be annoying to add logic in the delegate.
i.e. it generates something like this this::
datarow =>
new MyObject()
{
property1 = DBConverterCache<TProperty1>.Converter(datarow[columnName1]),
property2 = DBConverterCache<TProperty2>.Converter(datarow[columnName2]),
/*etc...*/
};
Even more so, I have another annoyance. Objects in the object layer may not match correctly to ones in the database. This is a problem because you can't unbox things to the "wrong" type. I.e. the property in the object layer is an Int32
, the column in the DB is an Int64
. To fix this I have for the struct IConvertibles the converter basically does this::
value => value == DBNull.Value ? default(T) : (value as IConvertible).To<Type*>(null);
* in the case of Nullable<T> or Enum it casts to underlying type, then casts up to T
This is ugly as we have to use reflection to generate the call to ToType
, which relies on the assumption that they will never expand the IConvertible interface to add more objects that are convertible. It's a hack but it avoids boxing the return type. Which a method like IConvertible.ToType does.
of course this works just as well:
value => value == DBNull.Value ? default(T) : (T)(value as dynamic);
Maybe even better, as I don't have to specialize the call based on the type I can just make that my default converter. The only issue I haven't a clue as to how to use Expression.Dynamic, and I can't create an expression that takes dynamic as a parameter. I suppose I could just bind it to a static method or the above lambda expression, but I'd like to do everything as expression trees, if possible.