参数化Linq表达式帮助

时间:2011-03-27 05:19:33

标签: c# linq linq-to-entities expression-trees

我想用这样的签名做一个方法:

Expression<Func<TSource, bool>> CreatePropertyFilter<TSource>(Expression<Func<TSource, string>> selector, string value, TextMatchMode matchMode);

基本上,它需要一个属性选择器(例如:p = p.Name),一个字符串值和一个枚举值,可以是StartsWithEndsWithContains,{{ 1}};用于文本匹配选项。

如何以LINQ2Entities可以理解的方式实现该方法?我已经使用嵌套的调用表达式实现了这个方法,如下所示:

Exact

问题是Linq2Entities不支持调用表达式。

对此有何建议?

谢谢!

1 个答案:

答案 0 :(得分:5)

基本上,给定一个选择器:

input => input.Member

您正在构建一个谓词表达式,如:

input => selector(input).Method(value)

相反,使用 body MemberExpression)'展开'选择器表达式,构造如下内容:

input => input.Member.Method(value) 

这看起来像是:

private static Expression<Func<TSource, bool>> CreatePropertyFilter<TSource>
    (Expression<Func<TSource, string>> selector, 
     string value, 
     TextMatchMode matchMode)
{
    // Argument-checking here.    

    var body = selector.Body as MemberExpression;

    if (body == null)
        throw new ArgumentException("Not a MemberExpression.");    

    // string.StartsWith / EndsWith etc. depending on the matchMode.
    var method = typeof(string)
                 .GetMethod(GetMethodName(matchMode), new[] { typeof(string) });

    // input.Member.method(value)
    var compEx = Expression.Call(body, method, Expression.Constant(value));

    // We can reuse the parameter of the source.
    return Expression.Lambda<Func<TSource, bool>>(compEx, selector.Parameters);
}

翻译方法是:

// I really don't like this enum.
// Why not explicitly include Equals as a member?
private static string GetMethodName(TextMatchMode mode)
{
    switch (mode)
    {
        case TextMatchMode.StartsWith:
            return "StartsWith";

        case TextMatchMode.EndsWith:
                return "EndsWith";

        case TextMatchMode.Contains:
            return "Contains";

        default:
            return "Equals";
    }    
}