【问题标题】:Get from IQueryable<T> predicate Func<T, bool>从 IQueryable<T> 谓词 Func<T, bool> 获取
【发布时间】:2015-06-25 18:23:08
【问题描述】:

我正在尝试将查询从一个集合应用到另一个集合。 我的测试样本:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        Expression sourceExpression = Amazings().Where(x => x.Name.Equals("Kasa")).AsQueryable().Expression;

        Expression<Func<Amazing, bool>> predicate = Expression.Lambda<Func<Amazing, bool>>(sourceExpression, Expression.Parameter(typeof(Amazing)));

        var col2 = Amazings().Where(predicate.Compile());
    }

    private IEnumerable<Amazing> Amazings()
    {
        var amazings = new List<Amazing>
            {
                new Amazing
                    {
                        Name = "Kasa",
                    },
                new Amazing
                    {
                        Name = "Ma@p2a"
                    }
            };
        return amazings;
    }

    class Amazing
    {
        public string Name { get; set; }
    }
}

怎么了? 当我在调试中运行这个测试时,我得到了异常:

对于返回类型“System.Boolean”,您不能使用诸如“System.Linq.EnumerableQuery`1[UnitTestProject1.UnitTest1+Amazing]”之类的表达式。

如果我在没有参数的情况下运行它,我会遇到我没有参数的异常。

如果我将参数更改为布尔类型,则会出现异常:您不能将元素 bool 类型用于委托参数类型 Amazing...

我测试了更多选项,但没有任何效果。

我还发现关键可以通过将 Expression 转换为:MethodCallExpression 但它不是,或者我无法确定如何。

我试过这样的东西:

MethodCallExpression e = query.Expression as MethodCallExpression;
        MemberExpression memberExpression = (MemberExpression)e.Object;

        Expression<Func<Amazing, bool>> getCallerExpression = Expression<Func<Amazing>>.Lambda<Func<Amazing, bool>>(memberExpression);

不幸的是 memberExpression 为空。

我在网上搜索,唯一发现的就是一个提示:~“不要这样做”

我怎样才能实现我的目标?

【问题讨论】:

    标签: c# linq expression iqueryable func


    【解决方案1】:

    由于您调用的是 Enumerable.Where 而不是 Queryable.Where,因此您拥有的 lambda 永远不会转换为 Expression,它只会编译成方法,而您拥有的 IQueryable 甚至没有获取该委托的任何方式,因为 看到的只是任意的IEnumerable&lt;T&gt;

    【讨论】:

      【解决方案2】:

      不清楚你想做什么......但正如Servy所写的那样,你把AsQueryable()放在了错误的地方。正确的位置是之前 .Where(),这是一个单元测试,我建议返回数据的方法应该直接返回一个IQueryable&lt;T&gt;,以便更好地模拟“正常”查询,你可以在代码中查找。

      试试看这是不是你想要的……

      public void TestMethod1()
      {
          var q1 = Amazings().Where(x => x.Name.Equals("Kasa"));
      
          Expression predicate = q1.Expression;
      
          var q2 = Amazings();
          IQueryable<Amazing> q3 = q2.Provider.CreateQuery<Amazing>(predicate);
      }
      
      private IQueryable<Amazing> Amazings()
      {
          var amazings = new List<Amazing>
          {
              new Amazing
                  {
                      Name = "Kasa",
                  },
              new Amazing
                  {
                      Name = "Ma@p2a"
                  }
          };
          return amazings.AsQueryable();
      }
      

      请注意,在最一般的情况下,您不能简单地移动 .Where()Expression&lt;Func&lt;Amazing, bool&gt;&gt; 条件,因为您可能有 .Where().Select() 或类似的东西。

      其他可能的解决方案,如果您知道最后一个方法是 .Where() 并且您真的想要“移动”Expression&lt;Func&lt;Amazing, bool&gt;&gt;

      MethodCallExpression mce = predicate as MethodCallExpression;
      
      if (mce == null)
      {
          throw new Exception();
      }
      
      UnaryExpression quote = mce.Arguments[1] as UnaryExpression;
      
      if (quote == null || quote.NodeType != ExpressionType.Quote)
      {
          throw new Exception();
      }
      
      Expression<Func<Amazing, bool>> lambda = quote.Operand as Expression<Func<Amazing, bool>>;
      
      if (lambda == null)
      {
          throw new Exception();
      }
      
      IQueryable<Amazing> q4 = Amazings().Where(lambda);
      

      【讨论】:

      • 谢谢,这正是我想要的! :) 不幸的是我不能点击“投票”,因为我没有足够的积分,但它确实有帮助:)
      猜你喜欢
      • 2013-03-09
      • 2021-06-17
      • 2011-03-18
      • 1970-01-01
      • 1970-01-01
      • 2020-08-05
      • 2017-07-02
      • 1970-01-01
      • 2020-12-22
      相关资源
      最近更新 更多