c# - 使用 Expression.Dynamic 为值类型生成转换器

标签 c# dynamic

我的应用程序的部分数据层是类似于 System.Data.DataRowExtensions.UnboxT 的转换器缓存, 在 Linq-to-Data 中使用。缓存所有已知类型的前提我生成一个简单的转换器并缓存它。转换器将对象转换为 T,或者在 DBNull.Value 的情况下, 返回 default(T) (与 UnboxT 不同,后者会在非可空值类型上引发异常。)我不能使用 UnboxT 的原因是我们的开发人员不喜欢在从数据行分配值之前检查 DBNull,他们只是希望它完成他们。 我们还有一个工厂来生成从 DataRow 实例化对象的助手委托(delegate),在委托(delegate)中添加逻辑会很烦人。 即它生成这样的东西::

datarow =>
    new MyObject()
    {
        property1 = DBConverterCache<TProperty1>.Converter(datarow[columnName1]),
        property2 = DBConverterCache<TProperty2>.Converter(datarow[columnName2]),
        /*etc...*/

    };

更何况,我还有一个烦恼。对象层中的对象可能无法与数据库中的对象正确匹配。这是一个问题,因为您不能将东西拆箱为“错误”类型。 IE。对象层中的属性是 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 接口(interface)来添加更多可转换对象的假设。这是一个 hack,但它避免了对返回类型进行装箱。 IConvertible.ToType 这样的方法可以做到这一点。

当然这也行得通:

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

也许更好,因为我不必根据我可以将其设为我的默认转换器的类型专门化调用。唯一的问题是我不知道如何使用 Expression.Dynamic,而且我无法创建将动态作为参数的表达式。我想我可以将它绑定(bind)到静态方法或上面的 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();
    }

似乎工作得很好。

关于c# - 使用 Expression.Dynamic 为值类型生成转换器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3909540/

相关文章:

c# - 检查路径是否在网络上

c# - 数据没有出现在特定的表中,只有一个表有数据

c# - Fluent Nhibernate List<string> 映射

java - 根据实际对象类型进行动态引用转换

c# - 如何编写使用从 C# 创建的临时表的存储过程

c# - ASP.net LoadAssembly 动态

python - 在spark Dataframe中动态创建多列

javascript - React-final-form-array如何根据新状态重新渲染表单

dynamic - 后期绑定(bind)与动态绑定(bind)

php - Javascript Tabber 重新加载