I have an expression tree function from a previous SO question. It basically allows the conversion of a data row into a specific class.
This code works fine, unless you're dealing with data types that can be bigger or smaller (eg. Int32/Int64).
The code throws an invalid cast exception when going from an Int64
to an Int32
when the value would fit in an Int32
(eg. numbers in the 3000).
Should I?
- Attempt to fix this in the code? (If so, any pointers?)
Leave the code as it is.
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(); }
Update:
I have now given up and decided it is not worth it. From the comments below, I got as far as:
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);
}
I don't think I was too far off, feel free to finish it and post the answer if you figure it out :)