Help, I appeared to wondered off the path somewhat.
After asking this question yesterday, I decided to take a look into expression trees. I found a nice little place to start and here is what I have so far:
// Gets the property type
ParameterExpression paramProperty = Expression.Parameter(property.PropertyType);
// Gets the value from row[0] (SqlDataReader)
ParameterExpression paramValue = Expression.Parameter(row[0].GetType());
// really no clue, makes a property so to speak?
MemberExpression prop = Expression.Property(paramProperty, property);
// assigns the property the value from the SqlDataReader
BinaryExpression assign = Expression.Assign(prop, paramValue);
// adds to an expression list ready for compilation
exps.Add(assign);
// allows things to be executed sequentially?
BlockExpression blockExpression = exps.Count > 0 ? Expression.Block(exps) : Expression.Block(Expression.Empty());
// create the parameter array
List<ParameterExpression> paramArr = new List<ParameterExpression>();
paramArr.Add(paramProperty);
paramArr.Add(paramValue);
// get a lambda so I can compile this for re-use
Expression<Action<T>> lamExp = Expression.Lambda<Action<T>>(blockExpression, paramArr);
First of all, are my comments right? I am piecing this information in the good old fashion way of a tutorial and msdn doc’s.
From the bits that I have been reading, I think I should have been able to compile this, store it in a dictionary with a type as the key and call it when I needed to. Eg.
ConcurrentDictionary<Type, ??> ExpressionCache;
if(ExpressionCache.ContainsKey(typeof(T))
{
// property is the variable of a foreach loop of type PropertyInfo
ExpressionCache[typeof(T)](property);
} // else do the first piece of code...
So in summary,
- Am I heading down the right track?
- Are my comments about the Expressions correct?
- What type should I use for the concurrent dictionary?
- When I cache the reference, how do I pass different parameters to the lambda?
Any improvements or suggestions are welcome as long as the are explained well. I am trying to understand how it works not just to make it work 🙂
It sounds like you’re looking for commentary more than anything else…right?
First of all, how will you have your SqlReader at compile time?
Your lambda takes two parameters though…so something is wrong (Action takes one parameter).
I would think that you really want is an
Func<SqlDataReader, T>. That way, you give it your SqlDataReader and it produces a T. So:I would store your cache as
Then cast it to the appropriate delegate type for the caller upon retrieval (have your method take a generic parameter:
So…as for your lambda builder/compiler:
Haven’t tested this, so please use with care and give it a try yourself.
I’m not sure if I got your intended usage correct…is it?