如何获取 IQueryable 中使用的方法和值?
How to get methods and values used in an IQueryable?
我正在尝试解析 IQueryable
,我想获取在 IQueryable
上调用的方法和参数。
例如
var query = Queryable.Skip(10).Take(100);
bool hasCalledSkipMethod = HasSkipMethod(query);
var skipValue = GetSkipMethodParameterValueSomeHow(query);
bool hasCalledTakeMethod = HasTakeMethod(query);
var takeValue = GetTakeMethodParameterValueSomeHow(query);
或者一些接收 IQueryable
和 returns 所有方法名称和参数的通用方法。
如何获取在 IQueryable
中应用的方法及其参数?
不确定这是否是最佳方法,但它可能会满足您的需求,或者至少可以指导您朝着正确的方向前进。
每个 IQueryable
都有一个 Expression
that represents the query to be executed as a tree data structure where each node is in itself also an Expression
. So whenever you do .Take(int)
in a IQueryable
what's happening behind the scenes is that a new Node of type MethodCallExpression
方法 Take(int)
被添加到那个 IQueryable
的表达式树中。
来自docs:
The Take(IQueryable, Int32) method generates a MethodCallExpression that represents calling Take(IQueryable, Int32) itself as a constructed generic method. It then passes the MethodCallExpression to the CreateQuery(Expression) method of the IQueryProvider represented by the Provider property of the source parameter.
因此,你要做的是遍历(访问树中的每个节点),看看是否有MethodCallExpression
类型的节点,其中方法在这种情况下,表达式的名称是 "Take"
.
要遍历表达式树,您可以创建一个 ExpressionVisitor
that overrides the method VisitMethodCall(MethodCallExpression)
。此自定义访问者可以接受要检查的方法名称作为构造函数参数,并且在访问节点时,如果方法名称是否找到,则存储在内部 属性 中。
有了自定义访客后,您可以调用 Visit(Expression)
where expression will be queryable.Expression
。
这是它的要点。
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
我正在尝试解析 IQueryable
,我想获取在 IQueryable
上调用的方法和参数。
例如
var query = Queryable.Skip(10).Take(100);
bool hasCalledSkipMethod = HasSkipMethod(query);
var skipValue = GetSkipMethodParameterValueSomeHow(query);
bool hasCalledTakeMethod = HasTakeMethod(query);
var takeValue = GetTakeMethodParameterValueSomeHow(query);
或者一些接收 IQueryable
和 returns 所有方法名称和参数的通用方法。
如何获取在 IQueryable
中应用的方法及其参数?
不确定这是否是最佳方法,但它可能会满足您的需求,或者至少可以指导您朝着正确的方向前进。
每个 IQueryable
都有一个 Expression
that represents the query to be executed as a tree data structure where each node is in itself also an Expression
. So whenever you do .Take(int)
in a IQueryable
what's happening behind the scenes is that a new Node of type MethodCallExpression
方法 Take(int)
被添加到那个 IQueryable
的表达式树中。
来自docs:
The Take(IQueryable, Int32) method generates a MethodCallExpression that represents calling Take(IQueryable, Int32) itself as a constructed generic method. It then passes the MethodCallExpression to the CreateQuery(Expression) method of the IQueryProvider represented by the Provider property of the source parameter.
因此,你要做的是遍历(访问树中的每个节点),看看是否有MethodCallExpression
类型的节点,其中方法在这种情况下,表达式的名称是 "Take"
.
要遍历表达式树,您可以创建一个 ExpressionVisitor
that overrides the method VisitMethodCall(MethodCallExpression)
。此自定义访问者可以接受要检查的方法名称作为构造函数参数,并且在访问节点时,如果方法名称是否找到,则存储在内部 属性 中。
有了自定义访客后,您可以调用 Visit(Expression)
where expression will be queryable.Expression
。
这是它的要点。
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