表达式树的转换问题

时间:2011-09-05 21:33:21

标签: c# expression-trees

我有一个先前SO问题的表达式树函数。它基本上允许将数据行转换为特定的类。

此代码工作正常,除非您处理的数据类型可能更大或更小(例如Int32 / Int64)。

当值从Int64变为Int32时,代码会抛出无效的强制转换异常(例如3000中的数字)。

我应该吗?

  1. 尝试在代码中修复此问题? (如果有,任何指针?)
  2. 保留代码原样。

    Int32

  3. 更新

    我现在放弃了,并认为这不值得。从下面的评论中,我得到了:

    private Func<SqlDataReader, T> getExpressionDelegate<T>()
    {
        // hang on to row[string] property 
        var indexerProperty = typeof(SqlDataReader).GetProperty("Item", new[] { typeof(string) });
    
        // list of statements in our dynamic method
        var statements = new List<Expression>();
    
        // store instance for setting of properties
        ParameterExpression instanceParameter = Expression.Variable(typeof(T));
        ParameterExpression sqlDataReaderParameter = Expression.Parameter(typeof(SqlDataReader));
    
        // create and assign new T to variable: var instance = new T();
        BinaryExpression createInstance = Expression.Assign(instanceParameter, Expression.New(typeof(T)));
        statements.Add(createInstance);
    
        foreach (var property in typeof(T).GetProperties())
        {
    
            // instance.MyProperty
            MemberExpression getProperty = Expression.Property(instanceParameter, property);
    
            // row[property] -- NOTE: this assumes column names are the same as PropertyInfo names on T
            IndexExpression readValue = Expression.MakeIndex(sqlDataReaderParameter, indexerProperty, new[] { Expression.Constant(property.Name) });
    
            // instance.MyProperty = row[property]
            BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(readValue, property.PropertyType));
            statements.Add(assignProperty);
        }
    
        var returnStatement = instanceParameter;
        statements.Add(returnStatement);
    
        var body = Expression.Block(instanceParameter.Type, new[] { instanceParameter }, statements.ToArray());
    
        var lambda = Expression.Lambda<Func<SqlDataReader, T>>(body, sqlDataReaderParameter);
    
        // cache me!
        return lambda.Compile();
    }
    

    我认为我离得太远,如果你弄明白的话,可以自由地完成它并发布答案:)

2 个答案:

答案 0 :(得分:3)

您可以尝试在分配之前通过“转换已检查”来修复它,即在值上使用Expression.ConvertChecked而不是Expression.Convert

现在无法尝试,但这应该照顾你描述的情况......

编辑 - 根据评论,这可能是拳击问题:

在这种情况下,您可以尝试使用Expression.TypeAsExpression.Unbox进行转化,或使用Expression.Call调用方法进行转换...使用{{1}的示例}可以在http://msdn.microsoft.com/en-us/library/bb349020.aspx

找到

答案 1 :(得分:1)

如果要在.NET和SQL中支持100%的原语,那么您尝试构建的内容实际上要复杂得多。

如果你不关心某些边缘情况(可空类型,枚举,字节数组等),那么有两个技巧可以让你获得90%:

不要在IDataRecord上使用索引器,它会返回一个对象,装箱/拆箱会杀死性能。相反,请注意IDataRecord上有Get [typeName]方法。这些存在于所有.NET基元类型中(注意:它是GetFloat,而不是GetSingle,非常烦人)。

您可以使用IDataRecord.GetFieldType来确定您需要为给定列调用哪个Get方法。完成后,可以使用Expression.Convert将DB列类型强制转换为目标属性的类型(如果它们不同)。对于那些你需要自定义逻辑的人来说,对于我上面列出的一些边缘情况,这将失败。