转换表达式< Func< T,T,bool>>对表达式< Func> T,bool> [英] Convert Expression<Func<T,T,bool>> to Expression<Func<T,bool>>

查看:68
本文介绍了转换表达式< Func< T,T,bool>>对表达式< Func> T,bool>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个这样的表情

(a,b) => a.Id == b.Id

我想在LINQ to Entities查询中使用它

I would like to use it in LINQ to Entities query

T GetSingle(IRepository<T> repository, Func<T,T,bool> predicate, T entity)
{
   return repository.GetAll().Single(e => predicate(e, entity))
}

但这会导致异常:LINQ to Entities不支持LINQ表达式节点类型'Invoke'
据我了解,我可以使用Expressions构造LINQ2SQL的Valide谓词,因此我的表达式 (a,b)=> a.Id == b.Id 和具有 Id = 5 的实体实例可以产生新的表达式(a)=> a.Id == 5 .
对于LINQ to Entities,最后一个表达式将是正确的.

but this results the exception: LINQ expression node type 'Invoke' is not supported in LINQ to Entities
As I understand I can use Expressions to construct a valide predicate for LINQ2SQL, so my expression (a,b) => a.Id == b.Id and instance of entity with Id = 5 can result a new expression (a) => a.Id == 5.
And the last expression will be fine for LINQ to Entities.

我找到并阅读了这篇文章
在lambda表达式中替换参数
http://www.codeproject.com/Articles/143096/表达树内的参数替换
但仍然不知道如何解决我的任务

I found and read this articles
Replace parameter in lambda expression
http://www.codeproject.com/Articles/143096/Parameter-Substitution-within-Expression-Trees
but still has no clue how to solve my task

那么,如何动态转换给定的表达式?

So, how do I convert given expression dynamically?

推荐答案

我尚未使用Linq2SQL对其进行过测试,但是在我看来,您应该能够使用表达式访问者来执行此操作并编译该表达式以编写将参数的值转换为您提供的表达式中的值(假设您切换为使用Expression<Func<T, T, bool>>而不是Func<T, T, bool>),并创建一个包装器,该包装器本身对GetAll

I haven't tested it with Linq2SQL, but it seems to me that you should be able to do this with an expression visitor and compiling the expression to write the value of your parameter into the expression you've supplied (assuming you switch over to using Expression<Func<T, T, bool>> instead of Func<T, T, bool>) and creating a wrapper that itself invokes Enumerable.Single on the result from the GetAll

访问者(对于您给出的示例,看起来像这样)

The visitor (for specifically the example you've given would look like this)

public class VariableSubstitutionVisitor : ExpressionVisitor
{
    private readonly ParameterExpression _parameter;
    private readonly ConstantExpression _constant;

    public VariableSubstitutionVisitor(ParameterExpression parameter, ConstantExpression constant)
    {
        _parameter = parameter;
        _constant = constant;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        if (node == _parameter)
        {
            return _constant;
        }

        return node;
    }
}

现在,我们将调整GetSingle方法,使其看起来像这样:

Now, we'd adjust the GetSingle method to look like this:

public T GetSingle(IRepository<T> repository, Expression<Func<T, T, bool>> predicate, T entity)
{
    //Create a new representation of predicate that will take just one parameter and capture entity

    //Get just the body of the supplied expression
    var body = predicate.Body;
    //Make a new visitor to replace the second parameter with the supplied value
    var substitutionVisitor = new VariableSubstitutionVisitor(predicate.Parameters[1], Expression.Constant(entity, typeof(T)));
    //Create an expression that represents the predicate with the second parameter replaced with the supplied entity
    var visitedBody = substitutionVisitor.Visit(body).Reduce();
    //Make the new expression into something that could be a Func<T, bool>
    var newBody = Expression.Lambda<Func<T, bool>>(visitedBody, predicate.Parameters[0]); 

    //Now, create something that will call Enumerable.Single on the result of GetAll from the repository, supplying the new predicate

    //Make a place to hold the result of GetAll
    var resultsParameter = Expression.Parameter(typeof (IEnumerable<T>));
    //Make an expression that calls the Single extension method
    var singleExpression = Expression.Call(((Func<IEnumerable<T>, Func<T, bool>, T>)Enumerable.Single).Method, resultsParameter, newBody);
    //Make a Func<IEnumerable<T>, T> that return the result of the call of Single on the results of the GetAll method
    var compiled = Expression.Lambda<Func<IEnumerable<T>, T>>(singleExpression, resultsParameter).Compile();
    //Call GetAll, letting the new method that we've got run the supplied predicate without having to run an Invoke type expression
    return compiled(repository.GetAll()); 
}

技巧当然是使它表现良好.

The trick, of course, is getting that to perform well.

这篇关于转换表达式&lt; Func&lt; T,T,bool&gt;&gt;对表达式&lt; Func&gt; T,bool&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆