Reputation: 11439
I have this code:
public static Func<IDataReader, T> CreateBinder<T>() {
NewExpression dataTransferObject = Expression.New(typeof(T).GetConstructor(Type.EmptyTypes));
ParameterExpression dataReader = Expression.Parameter(typeof(IDataReader), "reader");
IEnumerable<Expression> columnAssignments = typeof(T).GetProperties().Select(property => {
MethodCallExpression columnData = Expression.Call(dataReader, dataReaderIndexer, new[] { Expression.Constant(property.Name) });
MethodCallExpression setter = Expression.Call(dataTransferObject, property.SetMethod, new[] { Expression.Convert( columnData, property.PropertyType ) });
return setter;
});
columnAssignments = columnAssignments.Concat(new Expression[] { dataTransferObject });
BlockExpression assignmentBlock = Expression.Block(columnAssignments);
Func<IDataReader, T> binder = Expression.Lambda<Func<IDataReader, T>>(assignmentBlock, new[] { dataReader }).Compile();
return binder;
}
which long story short binds the properties on database row to <T>
. The problem is that when I want to use/return dataTransferObject
, it's instantiating a new copy each time. How do I just get the reference, without recreating the object?
Upvotes: 1
Views: 419
Reputation: 149108
I'd recommend using member intialization / binding expressions rather than a series of setters:
public static Func<IDataReader, T> CreateBinder<T>()
{
NewExpression dataTransferObject = Expression.New(typeof(T).GetConstructor(Type.EmptyTypes));
ParameterExpression dataReader = Expression.Parameter(typeof(IDataReader), "reader");
IEnumerable<MemberBinding > bindings = typeof(T).GetProperties().Select(property => {
MethodCallExpression columnData = Expression.Call(dataReader, dataReaderIndexer, new[] { Expression.Constant(property.Name) });
MemberBinding binding = Expression.Binding(property, Expression.Convert( columnData, property.PropertyType));
return binding;
});
Expression init = Expression.MemberInit(dataTransferObject, bindings);
Func<IDataReader, T> binder = Expression.Lambda<Func<IDataReader, T>>(init, new[] { dataReader }).Compile();
return binder;
}
Upvotes: 3
Reputation: 292765
You just need to assign the NewExpression
to a variable, and use that variable instead of the NewExpression
.
var dataTransferObject = Expression.Variable(typeof(T), "dto");
var assignment = Expression.Assign(
dataTransferObject,
Expression.New(typeof(T).GetConstructor(Type.EmptyTypes)));
(add these expressions to the BlockExpression
)
Upvotes: 3