c# - 如何获取 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
并返回所有方法名称和参数。
我怎样才能得到方法和它在一个中应用的参数IQueryable
?
解决方案
不确定这是否是最好的方法,但它可能适用于您想要的,或者至少可以引导您朝着正确的方向前进。
每个节点IQueryable
都有一个Expression
表示要作为树数据结构执行的查询,其中每个节点本身也是一个Expression
. 因此,每当您.Take(int)
在IQueryable
幕后发生的事情时,都会MethodCallExpression
将该方法的新类型节点Take(int)
添加到该的表达式树中IQueryable
。
从文档:
Take(IQueryable, Int32) 方法生成一个 MethodCallExpression,它表示调用 Take(IQueryable, Int32) 本身作为构造的泛型方法。然后它将 MethodCallExpression 传递给由源参数的 Provider 属性表示的 IQueryProvider 的 CreateQuery(Expression) 方法。
因此,您要做的是遍历(访问树中的每个节点)并查看是否存在MethodCallExpression
表达式的方法名称所在的类型的节点,在本例中为"Take"
.
要遍历表达式树,您可以创建一个ExpressionVisitor
覆盖方法VisitMethodCall(MethodCallExpression)
。此自定义访问者可以接受要检查的方法名称作为构造函数参数,并且在访问节点时,如果找到方法名称,则将其存储在内部属性中。
一旦有了自定义访问者,就可以调用Visit(Expression)
where 表达式 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
推荐阅读
- javascript - 切换组件上的类映射
- vb.net - vb.net 在 POST 中接收 json 数据,其中键有正斜杠
- c# - 用于匹配 HH:MM 和 HH:MM:SS 时间格式的正则表达式
- dart - 完成小部件动画后,在 Flutter 中运行一个函数
- javascript - NGXS - 某个善良的灵魂可以向我解释这种外星语法吗
- vba - 将宏作为加载项分发给其他用户
- ssh - 尝试通过 SSH 连接到谷歌云时出错
- python - Scikit-learn 的 LabelBinarizer 与 OneHotEncoder
- ansible - Packer 的 ansible-local 不会将 packer 变量作为额外的变量获取
- string - 如何将字符串从 CSV 列拆分为列表?