Звучит так, как будто вы ищете комментарии больше, чем что-либо еще ... верно?
Прежде всего, как у вас будет SqlReader во время компиляции?
// Gets the value from row[0] (SqlDataReader)
ParameterExpression paramValue = Expression.Parameter(Type.GetTypeFromHandle(row[0].GetType()));
Ваша лямбда принимает два параметра, хотя ... так что что-то не так (Действие принимает один параметр).
Я думаю, что вы действительно хотите это Func<SqlDataReader, T>
.Таким образом, вы даете ему свой SqlDataReader, и он выдает T. Итак:
var list = new List<T>();
// get a SqlDataReader
while (reader.Read())
{
Func<SqlDataReader, T> readRow = GetReader<T>();
list.Add(readRow(reader);
}
Я бы сохранил ваш кеш как
ConcurrentDictionary<Type, Delegate> ExpressionCache; // can't use T here since each Func will have a different T
Затем приведу его к соответствующему типу делегатавызывающий при извлечении (пусть ваш метод принимает универсальный параметр:
public Func<SqlDataReader, T> GetReader<T>()
{
Delegate d;
if(!ExpressionCache.TryGetValue(typeof(T), out d)
{
ExpressionCache[typeof(T)] = d = // build and compile lambda
}
// cast to strong typed delegate...we don't want to have to DynamicInvoke...that's slow
return (Func<SqlDataReader, T>)d;
}
Итак ... что касается вашего лямбда-компилятора / компилятора:
// 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());
/* so we end up with
* T Read(SqlDataReader row)
* {
* var x = new T();
* x.Prop1 = (cast)row["Prop1"]
* x.Prop2 = (cast)row["Prop2"]
* x.Prop3 = (cast)row["Prop3"]
* x.Prop4 = (cast)row["Prop4"]
* etc.
* return x
* }
*/
var lambda = Expression.Lambda<Func<SqlDataReader, T>>(body, sqlDataReaderParameter);
// cache me!
return lambda.Compile();
Не проверял это, поэтому, пожалуйста,используйте с осторожностью и попробуйте сами.
Я не уверен, правильно ли я понял ваше предполагаемое использование ... это так?