【问题标题】:Generic expression abstraction issue通用表达式抽象问题
【发布时间】:2014-01-30 08:11:15
【问题描述】:

我有以下方法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);

然后通过在实体框架 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 信息。

【问题讨论】:

  • 我错过了反射进来的地方。我在监督什么吗?
  • @PatrickHofman:我已经修改了这个问题。对此感到抱歉。
  • 哎呀。编辑在答案内。
  • @davenewza ChildEntities 是属性还是字段?
  • @Grundy:这是一个属性。

标签: c# .net lambda func linq-expressions


【解决方案1】:

您的两个实现之间的主要区别在于,第二个实现捕获方法参数,而第一个不捕获。参数作为字段存储在闭包中,并且该字段访问的存在可能会导致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 的值应该与您的第一个实现产生的值相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-05
    • 2011-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多