我有一个先前SO问题的表达式树函数。它基本上允许将数据行转换为特定的类。
此代码工作正常,除非您处理的数据类型可能更大或更小(例如Int32 / Int64)。
当值从Int64
变为Int32
时,代码会抛出无效的强制转换异常(例如3000中的数字)。
我应该吗?
保留代码原样。
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();
}
我认为我离得太远,如果你弄明白的话,可以自由地完成它并发布答案:)
答案 0 :(得分:3)
您可以尝试在分配之前通过“转换已检查”来修复它,即在值上使用Expression.ConvertChecked
而不是Expression.Convert
。
现在无法尝试,但这应该照顾你描述的情况......
编辑 - 根据评论,这可能是拳击问题:
在这种情况下,您可以尝试使用Expression.TypeAs
或Expression.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列类型强制转换为目标属性的类型(如果它们不同)。对于那些你需要自定义逻辑的人来说,对于我上面列出的一些边缘情况,这将失败。