我的应用程序的数据层的一部分是类似于Lincc-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,数据库中的列是Int64。为了解决这个问题,我对转换器的IConvertibles结构基本上做到了:

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

这很丑陋,因为我们必须使用反射来生成对ToType的调用,这依赖于这样的假设:它们永远不会扩展IConvertible接口来添加更多可转换的对象。这是一个hack,但是避免了将返回类型装箱。像IConvertible.ToType这样的方法。

当然,这同样适用:

value => value == DBNull.Value ? default(T) : (T)(value as dynamic);


甚至更好,因为我不必根据类型来专门调用,我可以将其设置为默认转换器。我不知道如何使用Expression.Dynamic的唯一问题,而且我无法创建将动态作为参数的表达式。我想我可以将其绑定到静态方法或上面的lambda表达式,但是如果可能的话,我想将所有内容都作为表达式树来做。

最佳答案

好吧,我有了一些好的旧反射器,使它可以工作。

    public static Converter<Object, T> CreateDynamicConverter<T>()
    {
        var param = Expression.Parameter(typeof(object));
        var expression = Expression.Lambda<Converter<object, T>>(
            Expression.Condition(
                Expression.Equal(
                    param,
                    Expression.Constant(
                        DBNull.Value
                    )
                ),
                Expression.Default(
                    typeof(T)
                ),
                Expression.Dynamic(
                    Binder.Convert(
                        CSharpBinderFlags.ConvertExplicit,
                        typeof(T),
                        typeof(MyApplicationNameHere)
                    ),
                    typeof(T),
                    param
                )
            ),
            param
        );
        return expression.Compile();
    }


似乎工作正常。

10-08 05:18
查看更多