C# 如何获取IQueryable中使用的方法和值?

C# 如何获取IQueryable中使用的方法和值?,c#,iqueryable,C#,Iqueryable,我正在尝试解析一个IQueryable,我想获得在IQueryable上调用的方法和参数 e、 g 或者某个通用方法,该方法接收IQueryable,并返回所有方法名称和参数 我如何才能获得在IQueryable中应用的方法及其参数?不确定这是否是最好的方法,但它可能会满足您的需要,或者至少会引导您朝着正确的方向前进 每个IQueryable都有一个表达式,表示要作为树数据结构执行的查询,其中每个节点本身也是一个表达式。因此,每当您在IQueryable中执行.Take(int)时,幕后发生的事

我正在尝试解析一个
IQueryable
,我想获得在
IQueryable
上调用的方法和参数

e、 g

或者某个通用方法,该方法接收
IQueryable
,并返回所有方法名称和参数


我如何才能获得在
IQueryable
中应用的方法及其参数?

不确定这是否是最好的方法,但它可能会满足您的需要,或者至少会引导您朝着正确的方向前进

每个
IQueryable
都有一个表达式,表示要作为树数据结构执行的查询,其中每个节点本身也是一个
表达式。因此,每当您在
IQueryable
中执行
.Take(int)
时,幕后发生的事情是,方法
Take(int)
的新节点类型被添加到该
IQueryable
的表达式树中

从:

Take(IQueryable,Int32)方法生成MethodCallExpression,该表达式将调用Take(IQueryable,Int32)本身表示为构造的泛型方法。然后,它将MethodCallExpression传递给由源参数的Provider属性表示的IQueryProvider的CreateQuery(Expression)方法

因此,您要做的是遍历(访问树中的每个节点)并查看是否有任何类型的节点,其中表达式的方法名在本例中为“Take”

要遍历表达式树,可以创建覆盖该方法的。此自定义访问者可以接受要检查的方法名称作为构造函数参数,并且在访问节点时,如果找到或未找到该方法名称,则将其存储在内部属性中

一旦有了自定义访问者,就可以调用where表达式

这里是它的要点

using System.Linq;
using System.Linq.Expressions;
                    
public class Program
{
    public static void Main()
    {       
        IQueryable<int> queryable = new []{ 78, 92, 100, 37, 81 }
            .AsQueryable()
            .Skip(1)
            .Take(2);

        Expression expression = queryable.Expression;
        
        var hasTakeMethodVisitor = new HasMethodVisitor("Take");
        var hasSkipMethodVisitor = new HasMethodVisitor("Skip");
        var hasWhereMethodVisitor = new HasMethodVisitor("Where");
        
        hasTakeMethodVisitor.Visit(expression);
        hasSkipMethodVisitor.Visit(expression);
        hasWhereMethodVisitor.Visit(expression);
        
        System.Console.WriteLine("Has Take Method? {0}", hasTakeMethodVisitor.HasMethod);
        System.Console.WriteLine("Has Skip Method? {0}", hasSkipMethodVisitor.HasMethod);
        System.Console.WriteLine("Has Where Method? {0}", hasWhereMethodVisitor.HasMethod);
    }
    
    internal class HasMethodVisitor : ExpressionVisitor {
        
        private readonly string _methodToFind;
        
        public HasMethodVisitor(string methodName) {
            _methodToFind = methodName;
        }
        
        public bool HasMethod { get; private set; }
        
        protected override Expression VisitMethodCall(MethodCallExpression node) {
            HasMethod |= node.Method.Name == _methodToFind;
        
            return base.VisitMethodCall(node);
        }
    }
}

你能进一步解释一下,例如,
GetSkipMethodSomeHow
需要做什么吗?@styx我刚刚编辑了方法名。它只需要检查它是否使用该方法(在本例中,如果调用了方法
Skip
),您可能需要检查lambda生成的表达式树的内容。下面是微软的一点解释:
using System.Linq;
using System.Linq.Expressions;
                    
public class Program
{
    public static void Main()
    {       
        IQueryable<int> queryable = new []{ 78, 92, 100, 37, 81 }
            .AsQueryable()
            .Skip(1)
            .Take(2);

        Expression expression = queryable.Expression;
        
        var hasTakeMethodVisitor = new HasMethodVisitor("Take");
        var hasSkipMethodVisitor = new HasMethodVisitor("Skip");
        var hasWhereMethodVisitor = new HasMethodVisitor("Where");
        
        hasTakeMethodVisitor.Visit(expression);
        hasSkipMethodVisitor.Visit(expression);
        hasWhereMethodVisitor.Visit(expression);
        
        System.Console.WriteLine("Has Take Method? {0}", hasTakeMethodVisitor.HasMethod);
        System.Console.WriteLine("Has Skip Method? {0}", hasSkipMethodVisitor.HasMethod);
        System.Console.WriteLine("Has Where Method? {0}", hasWhereMethodVisitor.HasMethod);
    }
    
    internal class HasMethodVisitor : ExpressionVisitor {
        
        private readonly string _methodToFind;
        
        public HasMethodVisitor(string methodName) {
            _methodToFind = methodName;
        }
        
        public bool HasMethod { get; private set; }
        
        protected override Expression VisitMethodCall(MethodCallExpression node) {
            HasMethod |= node.Method.Name == _methodToFind;
        
            return base.VisitMethodCall(node);
        }
    }
}
Has Take Method? True
Has Skip Method? True
Has Where Method? False