C# 转换表达式<;Func<;T、 T,bool>&燃气轮机;表达<;Func<;T、 布尔>&燃气轮机;

C# 转换表达式<;Func<;T、 T,bool>&燃气轮机;表达<;Func<;T、 布尔>&燃气轮机;,c#,linq-to-entities,C#,Linq To Entities,我有一个这样的表达 (a,b) => a.Id == b.Id public class VariableSubstitutionVisitor : ExpressionVisitor { private readonly ParameterExpression _parameter; private readonly ConstantExpression _constant; public VariableSubstitutionVisitor(Paramet

我有一个这样的表达

(a,b) => a.Id == b.Id
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;
    }
}
我想在LINQtoEntities查询中使用它

T GetSingle(IRepository<T> repository, Func<T,T,bool> predicate, T entity)
{
   return repository.GetAll().Single(e => predicate(e, entity))
}
T GetSingle(i存储库、Func谓词、T实体)
{
return repository.GetAll().Single(e=>predicate(e,entity))
}
但这会导致异常:LINQ to实体中不支持LINQ表达式节点类型“Invoke”
据我所知,我可以使用表达式为LINQ2SQL构造valide谓词,所以我的表达式 (a,b)=>a.Id==b.Id和具有Id=5的实体实例可以产生一个新表达式(a)=>a.Id==5
最后一个表达式适用于LINQ to实体

我找到并阅读了这篇文章


但仍然不知道如何解决我的任务


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

为什么不将方法更改为:

T GetSingle(IRepository<T> repository, Expression<Func<TSource, Boolean>> predicate)
{
   return repository.GetAll().Single(predicate);
}
您应该能够做到这一点:

GetSingle(myRepository, a => a.Id == myEntity.Id);

你为什么不把你的方法改成:

T GetSingle(IRepository<T> repository, Expression<Func<TSource, Boolean>> predicate)
{
   return repository.GetAll().Single(predicate);
}
您应该能够做到这一点:

GetSingle(myRepository, a => a.Id == myEntity.Id);

我还没有使用Linq2SQL对其进行测试,但在我看来,您应该能够使用表达式访问者完成这项工作,并编译表达式以将参数的值写入您提供的表达式中(假设您切换到使用
expression
而不是
Func
)并创建一个包装器,该包装器本身对来自
GetAll的结果调用
Enumerable.Single

访问者(具体来说,您给出的示例如下所示)

现在,我们将
GetSingle
方法调整为如下所示:

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()); 
}
public T GetSingle(i存储库、表达式谓词、T实体)
{
//创建谓词的新表示形式,该表示形式只接受一个参数并捕获实体
//只获取所提供表达式的主体
var body=谓词.body;
//创建一个新访问者,用提供的值替换第二个参数
var-substitutionVisitor=新变量substitutionVisitor(predicate.Parameters[1],Expression.Constant(entity,typeof(T));
//创建一个表示谓词的表达式,其中第二个参数替换为提供的实体
var visitedBody=substitutionVisitor.Visit(body.Reduce();
//将新表达式转换为可能是Func的内容
var newBody=Expression.Lambda(visitedBody,predicate.Parameters[0]);
//现在,创建一个调用Enumerable.Single的东西,它将根据存储库中GetAll的结果调用Enumerable.Single,并提供新的谓词
//在一个地方放置GetAll的结果
var resultsParameter=Expression.Parameter(typeof(IEnumerable));
//生成一个调用单扩展方法的表达式
var singleExpression=Expression.Call(((Func)Enumerable.Single).Method,resultsParameter,newBody);
//生成一个Func,返回对GetAll方法的结果调用Single的结果
var compiled=Expression.Lambda(singleExpression,resultsParameter.Compile();
//调用GetAll,让我们得到的新方法运行提供的谓词,而不必运行Invoke类型表达式
返回已编译(repository.GetAll());
}

当然,诀窍是让它运行良好。

我还没有用Linq2SQL对它进行测试,但在我看来,您应该能够使用表达式访问者完成这项工作,并编译表达式以将参数值写入您提供的表达式中(假设您切换到使用
Expression
而不是
Func
),并在
GetAll

访问者(具体来说,您给出的示例如下所示)

现在,我们将
GetSingle
方法调整为如下所示:

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()); 
}
public T GetSingle(i存储库、表达式谓词、T实体)
{
//创建谓词的新表示形式,该表示形式只接受一个参数并捕获实体
//只获取所提供表达式的主体
var body=谓词.body;
//创建一个新访问者,用提供的值替换第二个参数
var-substitutionVisitor=新变量substitutionVisitor(predicate.Parameters[1],Expression.Constant(entity,typeof(T));
//创建一个表示谓词的表达式,其中第二个参数替换为提供的实体
var visitedBody=substitutionVisitor.Visit(body.Reduce();
//将新表达式转换为可能是Func的内容
var newBody=Expression.Lambda(visitedBody,predicate.Parameters[0]);
//现在,创建一个调用Enumerable.Single的东西,它将根据存储库中GetAll的结果调用Enumerable.Single,并提供新的谓词
//在一个地方放置GetAll的结果
var resultsParameter=Expression.Parameter(typeof(IEnumerable));
//生成一个调用单扩展方法的表达式
var singleExpression=Expression.Call(((Func)Enumerable.Single).Method,resultsParameter,newBody);
//生成一个Func,返回对GetAll方法的结果调用Single的结果
var compiled=Expression.Lambda(singleExpression,resultsParameter.Compile();
//调用GetAll,让我们得到的新方法运行提供的谓词,而不必运行Invoke类型表达式
返回已编译(repository.GetAll());
}

当然,诀窍是让它表现得更好。

这更多的是理论上的兴趣而不是实践上的兴趣。现在有一些空闲时间,想研究表达式。很抱歉没有指出,更改方法签名不是解决方案。这更多的是理论上的兴趣而不是实践上的兴趣。现在有一些空闲时间,想研究表达式抱歉没有指出,更改方法签名不是解决方案