我有以下方法SetMapping(),该方法用于使用表达式定义一些映射设置。

public class AggregateMap<TDataEntity>
{
    protected Expression<Func<IUpdateConfiguration<TDataEntity>, object>> graphMapping;

    protected void SetMapping(Expression<Func<IUpdateConfiguration<TDataEntity>, object>> mapping)
    {
        graphMapping = mapping;
    }
}


调用代码示例:

SetMapping(map => map.OwnedCollection(root => root.ChildEntities));


上面的方法很好用,但是我想通过提供SetOwnedCollectionMapping()进一步抽象该方法。这意味着调用代码可以提供更多基本的表达式。

进一步抽象的方法:

protected void SetOwnedCollectionMapping<T>(Expression<Func<TDataEntity, ICollection<T>>> mapping)
{
    graphMapping = map => map.OwnedCollection<TDataEntity, T>(mapping);
}


调用代码示例:

SetOwnedCollectionMapping(root => root.ChildEntities);


然后,通过在Entity Framework DbContext实例上调用以下方法,在外部库(RefactorThis.GraphDiff)中使用此graphMapping字段:

public static void UpdateGraph<T>(this DbContext context, T entity, Expression<Func<IUpdateConfiguration<T>, object>> mapping) where T : class;


在运行时引发以下异常:


  类型“ System.InvalidCastException”的异常发生在
  RefactorThis.GraphDiff.dll,但未在用户代码中处理
  
  附加信息:无法转换类型的对象
  键入“ System.Reflection.RtFieldInfo”
  'System.Reflection.PropertyInfo'。


我一定会混淆我的通用类型,但是我看不到新旧实现之间的区别。

这是OwnedCollection方法的签名:

public static IUpdateConfiguration<T> OwnedCollection<T, T2>(this IUpdateConfiguration<T> config, Expression<Func<T, System.Collections.Generic.ICollection<T2>>> expression);


编辑:添加UpdateGraph信息来提问。

最佳答案

两种实现之间的主要区别在于,第二种实现捕获方法参数,而第一种捕获不到方法参数。该参数作为字段存储在闭包中,并且该字段访问的存在可能在RefactorThis.GraphDiff.dll中引起问题。

尝试如下更改第二种实现:

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);
}


这样,graphMapping的值应与第一个实现产生的值相同。

10-04 10:23