IQueryable表达式类型不匹配

时间:2018-03-23 14:16:25

标签: c# reflection expression system.reflection

我想为LINQ表达式创建一个扩展方法但是我被卡住了。我需要的只是创建一个方法,将一个特定的 Where 子句添加到Queryable。类似的东西:

var hierarchy = "a string";
Session.Query<SomeClass>.Where(x => x.Layer.Hierarchy.StartsWith(hierarchy) ||
                                    x.Layer.Hierarchy == hierarchy);

成为:

var hierarchy = "a string";
Session.Query<SomeClass>.LayerHierarchy(x => x.Layer, hierarchy);

做那里的逻辑。基本上,扩展方法LayerHierarchy()正在Queryable T上运行,但主题类型为Layer

public static IQueryable<T> LayerHierarchy<T>(this IQueryable<T> query,
                                                  Expression<Func<T, Layer>> layer,
                                                  string hierarchy)

{
    var parameterExp = Expression.Parameter(typeof(Layer), "layer");
    var propertyExp = Expression.Property(parameterExp, "Hierarchy");

    // StartWith method
    MethodInfo methodStartsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
    var valueStartsWith = Expression.Constant(string.Concat(hierarchy, "|"), typeof(string));

    var methodExpStartsWith = Expression.Call(propertyExp, methodStartsWith, valueStartsWith);
    var startsWith = Expression.Lambda<Func<Layer, bool>>(methodExpStartsWith, parameterExp);

    // Equals method
    MethodInfo methodEquals = typeof(string).GetMethod("Equals", new[] { typeof(string) });
    var valueEquals = Expression.Constant(hierarchy, typeof(string));

    var methodExpEquals = Expression.Call(propertyExp, methodEquals, valueEquals);
    var equals = Expression.Lambda<Func<Layer, bool>>(methodExpEquals, parameterExp);

    return query
                .Where(startsWith)
                .Where(equals);
}

一切都在return行之上正常工作。它抱怨......

  

无法从System.Linq.Expressions.Expression<System.Func<Layer, bool>>转换为System.Linq.Expressions.Expression<System.Func<T, int, bool>>

尝试将表达式传递给query.Where()方法时。我该如何解决?

1 个答案:

答案 0 :(得分:1)

嗯,问题是你如何创建Lambda。它们应该从T开始,而不是从Layer开始:

var startsWith = Expression.Lambda<Func<T, bool>>(methodExpStartsWith, parameterExp);
var equals = Expression.Lambda<Func<T, bool>>(methodExpEquals, parameterExp);

但是,为了实现这一点,您又错过了一个PropertyExpression

您的查询现在看起来像:

  

(层)x =&gt; x.Hierarchy.StartsWith(...)

什么时候,你想要的是这个:

  

(T)x =&gt; x.Layer.Hierarchy.StartsWith(...)

所以,请改用:

var parameterExp = Expression.Parameter(typeof(T), "item");
var layerExp = Expression.Property(parameterExp, "Layer");
var propertyExp = Expression.Property(layerExp, "Hierarchy");

你的逻辑应该稍微改变一下,因为两个.Where会在它们之间产生AND条件,看起来你想要其中一个是真的(StartsWith或{ {1}}),所以:

Equals