Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 参数为复杂对象时的参数替换_C#_Linq_Expression Trees_Expressionvisitor - Fatal编程技术网

C# 参数为复杂对象时的参数替换

C# 参数为复杂对象时的参数替换,c#,linq,expression-trees,expressionvisitor,C#,Linq,Expression Trees,Expressionvisitor,我正在尝试创建一个动态AndAlso过滤器,该过滤器将在Where方法中用于LINQ to EF查询: query.Where(filterExpression) 其中,filterExpression是一个已编译的lambda 到目前为止,我已经实现了一个具有一些奇特用法的循环,用于检查只有一个、两个或多个查询的情况 Expression selectLeft = null; Expression selectRight = null; Expression filterExpression

我正在尝试创建一个动态
AndAlso
过滤器,该过滤器将在
Where
方法中用于
LINQ to EF
查询:

query.Where(filterExpression)
其中,
filterExpression
是一个已编译的lambda

到目前为止,我已经实现了一个具有一些奇特用法的循环,用于检查只有一个、两个或多个查询的情况

Expression selectLeft = null;
Expression selectRight = null;
Expression filterExpression = null;

foreach (QueryColumn columnQuery in querycolumns)
{
    Expression<Func<FileColumnRecords, bool>> 
                columnPredicate = d => d.fcv.Any(f => (f.value != null ? 
                                  f.value.ToLower().Contains(columnQuery.queryTerm.ToLower()) :
                                  false));

    if (selectLeft == null)
    {
        selectLeft = columnPredicate.Body;
        filterExpression = selectLeft;
        continue;
    }
    if (selectRight == null)
    {
        selectRight = columnPredicate.Body;
        filterExpression =
        Expression.AndAlso(selectLeft, selectRight);
        continue;
    }

    filterExpression =
            Expression.AndAlso(filterExpression, columnPredicate.Body);
}
它由以下各项构成:

class ParameterReplacer : ExpressionVisitor
{
    private readonly ParameterExpression parameter;

    internal ParameterReplacer(ParameterExpression parameter)
    {
        this.parameter = parameter;
    }

    protected override Expression VisitParameter
        (ParameterExpression node)
    {
        return parameter;
    }
}
ParameterReplace
class由提供)

运行
ParameterReplace
时,出现以下错误:

"Property 'System.String value' is not defined for type 'Models.FileColumnRecords'"
其中
FileColumnRecords
定义为:

public class FileColumnRecords
{       
    public Documents doc;

    public IEnumerable<FileColumnValues> fcv;
}

我猜想,由于表达式树中嵌入了参数,所以您遇到了困难。替换程序应仅替换顶级参数

您可以将顶级表达式传递到
ParameterReplace

class ParameterReplacer : ExpressionVisitor
{
    private readonly ParameterExpression target;
    private readonly ISet<ParameterExpression> sources;

    internal ParameterReplacer(ParameterExpression target,
                               IEnumerable<LambdaExpression> expressions)
    {
        this.target = target;
        sources = new HashSet<ParameterExpression>(
            expressions.SelectMany(e => e.Parameters));
    }

    protected override Expression VisitParameter
        (ParameterExpression node)
    {
        return sources.Contains(node) ? target : node;
    }
}
类参数replacer:ExpressionVisitor
{
私有只读参数表达式目标;
专用只读ISet源;
内部ParameterReplace(ParameterExpression目标,
(可数表达式)
{
this.target=目标;
sources=新哈希集(
expressions.SelectMany(e=>e.Parameters));
}
受保护的重写表达式VisitParameter
(ParameterExpression节点)
{
返回源。包含(节点)?目标:节点;
}
}
然后,您需要更改代码的其余部分,以建立已组合的表达式树列表。当然还有更优雅的方式,但我认为这应该行得通。这是我脑子里想不出来的,我还没试过

说了这么多,你确定你不能只用它来代替吗?

基于JonSkeet的观点,我使用了JonSkeet从库中建议的一种惊人的方法,提出了以下简单的解决方案:

public static IQueryable<FileColumnRecords> DynamicColumnQuery
                                (this IQueryable<FileColumnRecords> query, 
                                List<QueryColumn> querycolumns)
{
    var predicate = PredicateBuilder.False<FileColumnRecords>();
    foreach (QueryColumn columnQuery in querycolumns)
    {
        string temp = columnQuery.queryTerm.ToLower();
        predicate = predicate.Or(d => d.fcv.Any(f => (f.value != null ?
                                 f.value.ToLower().Contains(temp) : false));
    }

    return query.AsExpandable().Where(predicate);
}
公共静态IQueryable动态列查询
(此IQueryable查询,
列表查询列)
{
var predicate=PredicateBuilder.False();
foreach(QueryColumn column在querycolumns中查询)
{
string temp=columnQuery.queryTerm.ToLower();
谓词=谓词。或(d=>d.fcv.Any)(f=>(f.value!=null?
f、 value.ToLower()包含(temp:false));
}
返回query.AsExpandable().Where(谓词);
}
如果您对编写表达式树略知一二,那么您将立即体会到这是多么令人难以置信的AWESOME。另外,请注意我是如何在谓词中嵌入参数的

我与LINQKit、Joseph或Ben Albahari的开发者没有任何关系 也不是O'Reilly出版社。只是一个非常满意的开发人员,他认为我应该 分享他们建造的令人敬畏的建筑


谢谢你的回复,Jon!
PredicateBuilder
看起来真的很有趣。你认为可以将我的整个
ColumnPricate
传递给
PredicateBuilder
或者我必须按照你在回答中的建议构建一个表达式树吗?@Seacookie:我不太明白你在做什么,但我怀疑你可以整个
columnPredicate
。这绝对值得一试。让我把这个拿出来试驾。天哪,Jon!
PredicateBuilder
真是太棒了!!谢谢你。
class ParameterReplacer : ExpressionVisitor
{
    private readonly ParameterExpression target;
    private readonly ISet<ParameterExpression> sources;

    internal ParameterReplacer(ParameterExpression target,
                               IEnumerable<LambdaExpression> expressions)
    {
        this.target = target;
        sources = new HashSet<ParameterExpression>(
            expressions.SelectMany(e => e.Parameters));
    }

    protected override Expression VisitParameter
        (ParameterExpression node)
    {
        return sources.Contains(node) ? target : node;
    }
}
public static IQueryable<FileColumnRecords> DynamicColumnQuery
                                (this IQueryable<FileColumnRecords> query, 
                                List<QueryColumn> querycolumns)
{
    var predicate = PredicateBuilder.False<FileColumnRecords>();
    foreach (QueryColumn columnQuery in querycolumns)
    {
        string temp = columnQuery.queryTerm.ToLower();
        predicate = predicate.Or(d => d.fcv.Any(f => (f.value != null ?
                                 f.value.ToLower().Contains(temp) : false));
    }

    return query.AsExpandable().Where(predicate);
}