使用 Expression.Dynamic 生成值类型的转换器
我的应用程序的数据层的一部分是类似于 Linq-to-Data 中使用的 System.Data.DataRowExtensions.UnboxT 的转换器缓存。缓存所有已知类型的前提是我生成一个简单的转换器并缓存它。转换器将对象转换为 T,或者在 DBNull.Value
的情况下,返回 default(T)
(与抛出异常的 UnboxT
不同)我不能使用 UnboxT 的原因是我们的开发人员不喜欢在从数据行分配值之前检查 DBNull,他们只是希望为他们完成此操作。 我们还有一个工厂来生成帮助程序委托,该委托从 DataRow 实例化对象,并且在委托中添加逻辑会很烦人。 即它会生成这样的东西::
datarow =>
new MyObject()
{
property1 = DBConverterCache<TProperty1>.Converter(datarow[columnName1]),
property2 = DBConverterCache<TProperty2>.Converter(datarow[columnName2]),
/*etc...*/
};
更重要的是,我还有另一个烦恼。对象层中的对象可能与数据库中的对象不正确匹配。这是一个问题,因为您无法将东西拆箱为“错误”类型。即对象层中的属性是Int32
,DB中的列是Int64
。为了解决这个问题,我对 struct IConvertibles 转换器基本上执行以下操作::
value => value == DBNull.Value ? default(T) : (value as IConvertible).To<Type*>(null);
* 在 Nullable
这很丑陋,因为我们必须使用反射来生成对 ToType
的调用,这依赖于它们永远不会扩展的假设IConvertible 接口添加更多可转换对象。这是一个 hack,但它避免了对返回类型的装箱。像 IConvertible.ToType 这样的方法就是这样做的。
当然,这也同样有效:
value => value == DBNull.Value ? default(T) : (T)(value as dynamic);
也许甚至更好,因为我不必根据类型专门化调用,我可以将其设为默认转换器。唯一的问题是我不知道如何使用 Expression.Dynamic,并且无法创建以动态作为参数的表达式。我想我可以将它绑定到静态方法或上面的 lambda 表达式,但如果可能的话,我希望将所有操作都作为表达式树进行。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好吧,我用一些旧的反光镜让它工作了。
似乎工作得很好。
Well I got this to work, with some good old reflector.
Seems to be working just fine.