表达式树的转换问题
本文关键字:问题 转换 表达式 | 更新日期: 2023-09-27 18:07:45
我有一个来自前一个SO问题的表达式树函数。它基本上允许将数据行转换为特定的类。
这段代码工作得很好,除非你处理的数据类型可以更大或更小(例如:Int32/Int64)。
当从Int64
转到Int32
时,代码抛出一个无效强制转换异常,而该值适合Int32
(例如。
我应该吗?
- 尝试在代码中修复此问题?(如果有,有什么提示吗?)
-
代码保持原样
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(); }
更新:
我现在已经放弃了,觉得不值得。从下面的评论中,我得到了:
if (readValue.Type != property.PropertyType)
{
BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(Expression.Call(property.PropertyType, "Parse", null, new Expression[] { Expression.ConvertChecked(readValue, typeof(string)) }), property.PropertyType));
statements.Add(assignProperty);
}
else
{
// instance.MyProperty = row[property]
BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(readValue, property.PropertyType));
statements.Add(assignProperty);
}
我不认为我做得太远了,如果你想明白了,请随意完成并发布答案:)
您可以尝试在分配之前通过"转换检查"来修复它,即使用Expression.ConvertChecked
而不是Expression.Convert
。
现在无法尝试,但这应该会照顾到你描述的情况…
编辑-根据评论,这可能是一个装箱问题:
在这种情况下,您可以尝试使用Expression.TypeAs
或Expression.Unbox
进行转换或使用Expression.Call
调用方法来进行转换…可以在http://msdn.microsoft.com/en-us/library/bb349020.aspx
Call
的示例。如果你想要支持。net和SQL中100%的原语,那么你试图构建的东西实际上要复杂得多。
如果你不关心一些边缘情况(可空类型,枚举,字节数组等),两个技巧可以让你达到90%:
不要在IDataRecord上使用索引器,它返回一个对象,并且装箱/拆箱会降低性能。相反,请注意IDataRecord上有Get[typeName]方法。这些存在于所有。net基本类型(注意:它是GetFloat,而不是GetSingle,非常烦人)。
你可以使用IDataRecord。GetFieldType来确定需要为给定列调用哪个Get方法。一旦你有了这些,你就可以使用Expression了。转换将DB列类型强制转换为目标属性的类型(如果它们不同)。对于我上面列出的一些边缘情况,对于那些需要自定义逻辑的情况,这将失败。