c# - 通用表达式抽象问题

标签 c# .net lambda func linq-expressions

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

运行时抛出以下异常:

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'.

我一定混淆了我的泛型类型,但我看不出新旧实现之间的区别。

这是 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 的值应该与您的第一个实现生成的值相同。

关于c# - 通用表达式抽象问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21450933/

相关文章:

c# - linq to sql查询使用方法

c# - 如何使用 ASP.NET Identity(Web 表单)将数据保存在数据库中?

c# - 如何从 websocket-sharp 客户端将文件发送到 SignalR hub?

c# - 使用 FakeItEasy,是否可以创建一个采用泛型类型参数的虚拟对象

c# - 连接的 Lambda 表达式

java - 如何在 Java 8 中使用方法引用从非静态类调用非静态方法?

c# - 如何更新 Azure 通知中心注册中的过期时间?

.net - 使用 MSBuild 时不构建私有(private)访问器

c++ - 创建共享 packaged_task 接受带转发的参数

c# - 如何为多部分表单数据及其值形成WebRequest?