【问题标题】:C# Linq extract Where clauseC# Linq 提取 Where 子句
【发布时间】:2017-08-30 14:15:17
【问题描述】:

我有以下 Linq 查询:

var query1 = qble1.Where(x => x.name == "name" && x.id == 1);

我正在尝试将Where 子句提取到一个变量中,然后我可以在需要时将其重新应用于另一个查询。

为了给你一个稍微不同的观点(希望不要混淆问题的目的),我可以做以下事情:

Expression<Func<testClass, bool>> whereClause = x => x.name == "name" && x.id == 1;             

var query1 = qble1.Where(whereClause);

这会将whereClause 变量应用于query1

我正在尝试实现与上述相反的操作,即编写查询,并将 Where 子句提取到变量 whereClause 中,例如

Expression<Func<testClass, bool>> whereClause = WhereClause of query1

这个可以吗?

我尝试这样做的原因是为了解决我在这个问题中遇到的问题:

C# Predicate builder with using AND with OR

【问题讨论】:

  • 是的,您可以将其作为静态调用表达式中的第二个参数。如果你知道你想要什么覆盖,你可以通过名称来识别它。
  • 换句话说,通过检查结果IEnumerable&lt;T&gt;来检索传递给Enumerable.Wherepredicate参数?
  • @vc74 听起来对我来说是正确的
  • @FilipCordas 你能提供更多细节吗,我不完全理解你的评论
  • @Alex 你为什么要这么做?为什么不直接构建谓词然后分配它们?

标签: c# linq where


【解决方案1】:

在答案中关于 IEnumerable 和 IQueryable 的答案中存在很多混淆,因此我会尽力提供帮助。首先,IEnumerables 使用编译的代码,而 IQueryable 使用表达式。 Expression 部分可在任何具有 Expression 属性的 IQueryable 中访问。它将用 Linq 表达式树代表您的代码。您可以通过这样的访问者获取该表达式的 where 部分。

  static void Main(string[] args)
        {
            var data = new [] 
            {
                new TestClass{ A = "A" },
                new TestClass{ A = "" },
                new TestClass{ A = "" },
                new TestClass{ A = "" },
                new TestClass{ A = "" }
            };

            var queryData = data.AsQueryable();

            queryData = queryData.
                Where(a => a.A == "A").OrderBy(a => a.A);


            Expression<Func<TestClass, bool>> filter = ( new  ExpressionGetter<Func<TestClass, bool>>()).GetWhere(queryData);

            Console.ReadLine();
        }

        public class ExpressionGetter<T> : ExpressionVisitor
        {
            private Expression<T> filter;

            protected override Expression VisitMethodCall(MethodCallExpression node)
            {
                if (node.Method.Name == "Where")
                {
                    var a = node.Arguments[1] as UnaryExpression;
                    filter = (Expression<T>)a.Operand;

                    return node;
                }
                else
                {
                    return base.VisitMethodCall(node);
                }
            }

            public Expression<T> GetWhere<TElement>(IQueryable<TElement> queryData) 
            {
                filter = null;

                this.Visit(queryData.Expression);

                return filter;
            }
        }

但是这是一个简单的例子,它会让你第一个找到它,但是一个 Queriable 可以有多个 wheres 转换等等。我认为 IEnumerable 不可能做到这一点,因为委托引用仅存在于您正在调用的方法的上下文中。

【讨论】:

  • 很好的答案,并解决了实际问题
  • @Alex 请记住尽可能多地对此进行测试,这更像是一种概念证明,我确信我错过了一些可能发生的情况。
  • 是的,当然 - 我昨天测试了它,一切似乎都在工作 - 它完全按照我想要的情况返回 lambda 表达式。
【解决方案2】:

我有以下 Linq 查询:
var query1 = qble1.Where(x =&gt; x.name == "name" &amp;&amp; x.id == 1);
我正在尝试Where 子句提取到一个变量中,然后我可以在需要时将其重新应用于另一个查询。

这是什么意思?你的意思是,提取提供的 lambda x =&gt; x.name == "name" &amp;&amp; x.id == 1?如果是这种情况,您可以简单地将这个 lambda 存储在一个变量中。 var a = x =&gt; x.name == "name" &amp;&amp; x.id == 1

为了给您一个稍微不同的观点(希望不会混淆问题的目的),我可以执行以下操作:
Expression&lt;Func&lt;testClass, bool&gt;&gt; whereClause = x =&gt; x.name == "name" &amp;&amp; x.id == 1;
var query1 = qble1.Where(whereClause);
这会将whereClause 变量应用于query1

不,如果qble1IEnumerable&lt;T&gt;,则不会编译。您正在传递一个 Expression ,其中需要一个函数或 lambda。现在你可以做whereClause.Compile() 如果这是你想要的,然后它会再次将whereClause 应用到qble1 而不是query1

我正在尝试实现上面的逆操作,即编写查询,然后将 Where 子句提取到变量whereClause 例如
Expression&lt;Func&lt;testClass, bool&gt;&gt; whereClause = WhereClause of query1

这是什么意思?你问给定一个IEnumerable&lt;T&gt;query1,你能提取用于获得IEnumerable&lt;T&gt; 的lambda/函数吗?这有意义吗?

您将术语where clauseLINQExpressionlambda 一起使用,很难理解这意味着什么。您应该改写您的问题,但我已尝试回答提出的字面问题

【讨论】:

    【解决方案3】:

    这个where 子句是一个 lambda 表达式。参考这个answer来实现这个

    【讨论】:

    • 这个评论比回答好。
    【解决方案4】:

    Func&lt;IQueryable&lt;TestClass&gt;,IQueryable&lt;TestClass&gt; filterFunc = query =&gt; query.Where(x =&gt; x.name == "name" &amp;&amp; x.id == 1);

    用法:

    var refinedSet = filterFunc(originalSet);

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-21
      • 1970-01-01
      相关资源
      最近更新 更多