I have the following method SetMapping()
which is used to define some mapping setting using expressions.
public class AggregateMap<TDataEntity>
{
protected Expression<Func<IUpdateConfiguration<TDataEntity>, object>> graphMapping;
protected void SetMapping(Expression<Func<IUpdateConfiguration<TDataEntity>, object>> mapping)
{
graphMapping = mapping;
}
}
Example calling code:
SetMapping(map => map.OwnedCollection(root => root.ChildEntities));
The above works great, but I would like to abstract this method a bit further by providing SetOwnedCollectionMapping()
. This means the calling code can provide a much more basic expression.
Further abstracted method:
protected void SetOwnedCollectionMapping<T>(Expression<Func<TDataEntity, ICollection<T>>> mapping)
{
graphMapping = map => map.OwnedCollection<TDataEntity, T>(mapping);
}
Example calling code:
SetOwnedCollectionMapping(root => root.ChildEntities);
This graphMapping
field is then used in an external library (RefactorThis.GraphDiff) by calling the following method on a Entity Framework DbContext instance:
public static void UpdateGraph<T>(this DbContext context, T entity, Expression<Func<IUpdateConfiguration<T>, object>> mapping) where T : class;
The following exception is being thrown at run-time:
An exception of type 'System.InvalidCastException' occurred in RefactorThis.GraphDiff.dll but was not handled in user code
Additional information: Unable to cast object of type 'System.Reflection.RtFieldInfo' to type 'System.Reflection.PropertyInfo'.
I must be confusing my generic types up, but I cannot see the difference between the old and new implementations.
Here is the signature for the OwnedCollection
method:
public static IUpdateConfiguration<T> OwnedCollection<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, System.Collections.Generic.ICollection<T2>>> expression);
EDIT: Added UpdateGraph
info to question.
The key difference between your two implementations is that the second captures a method parameter, while the first does not. The parameter gets stored as a field in a closure, and the presence of that field access is probably causing problems in RefactorThis.GraphDiff.dll
.
Try changing the second implementation as follows:
protected void SetOwnedCollectionMapping<T>(Expression<Func<TDataEntity, ICollection<T>>> mapping)
{
//
// Hack to resolve the `OwnedCollection` extension method.
//
Expression<Func<IUpdateConfiguration<TDataEntity>, object>> template =
_ => _.OwnedCollection(mapping);
var map = Expression.Parameter(
typeof(IUpdateConfiguration<TDataEntity>),
"map");
graphMapping = Expression.Lambda<Func<IUpdateConfiguration<TDataEntity>, object>>(
Expression.Call(
((MethodCallExpression)template.Body).Method,
map,
Expression.Quote(mapping)),
map);
}
The value of graphMapping
should then be identical to that produced by your first implementation.
来源:https://stackoverflow.com/questions/21450933/generic-expression-abstraction-issue