c# – 表达式树解析,变量最终成为常量
所以我正在开发一个需要解析表达式树的项目.我得到了大部分工作,但我遇到了一些问题.
我一直在关注表达树上的StackOverflow上的其他问题,但似乎无法找到我的问题的答案,所以这里. 我的问题是常量和变量之间的差异(或缺乏).让我从一个例子开始: user => user.Email == email 这显然不是常量而是变量,但这最终成为表达式树中某处的ConstantExpression.如果你看看表达式本身,它看起来有点奇怪: Expression = {value(stORM.Web.Security.User+<>c__DisplayClassa)} 如果我们再举一个例子: task => task.Status != TaskStatus.Done && t.Status != TaskStatus.Failed 这里我使用的是ENUM(TaskStatus). 所以我的问题是,在树解析中,我似乎在两种情况下都得到了一个ConstantExpression,我真的需要能够区分它们.这些只是示例,所以我要问的是一种通用的方式来告诉这两种类型的表达式,所以我可以在解析时以两种不同的方式处理. 编辑:好吧,我的例子可能不太清楚,所以我会再试一次.第一个例子: 用户user = db.Search<用户> (u => u.Email == email); 我正在尝试找到具有给定电子邮件地址的用户.我正在将其解析为一个存储过程,但除此之外,我猜. 第二个例子: IList<任务> tasks = db.Search(t => t.Status!= TaskStatus.Done&& t.Status!= TaskStatus.Failed); 在这里,我试图找到状态与“完成”和“失败”不同的所有任务. 再次感谢 解决方法
因此,从表达的角度来看,价值是一个常数.它不能被表达式改变.
你所拥有的是一个可能打开的闭包 – 即值可以在表达式的执行之间改变,但不能在它期间改变.所以这是一个“常数”.这是函数式编程和非函数式编程之间的范式差异. 考虑 int a =2; Expression<Func<int,int>> h = x=> x+ a; Expression<Func<int,int>> j = x => x +2; a = 1; 术语a是对匿名类的成员访问,该匿名类包装并访问堆栈上的变量.第一个节点是一个MemberAccess节点,然后在其下面 – 表达式是一个常量. 对于上面的代码: ((SimpleBinaryExpression)(h.Body)).Right {value(WindowsFormsApplication6.Form1+<>c__DisplayClass0).a} CanReduce: false DebugView: ".Constant<WindowsFormsApplication6.Form1+<>c__DisplayClass0>(WindowsFormsApplication6.Form1+<>c__DisplayClass0).a" Expression: {value(WindowsFormsApplication6.Form1+<>c__DisplayClass0)} Member: {Int32 a} NodeType: MemberAccess Type: {Name = "Int32" FullName = "System.Int32"} 而下面的常数: ((MemberExpression)((SimpleBinaryExpression)(h.Body)).Right).Expression {value(WindowsFormsApplication6.Form1+<>c__DisplayClass0)} CanReduce: false DebugView: ".Constant<WindowsFormsApplication6.Form1+<>c__DisplayClass0>(WindowsFormsApplication6.Form1+<>c__DisplayClass0)" NodeType: Constant Type: {Name = "<>c__DisplayClass0" FullName = "WindowsFormsApplication6.Form1+<>c__DisplayClass0"} Value: {WindowsFormsApplication6.Form1.} } } 普通的老2出来了: ((SimpleBinaryExpression)(j.Body)).Right {2} CanReduce: false DebugView: "2" NodeType: Constant Type: {Name = "Int32" FullName = "System.Int32"} Value: 2 所以我不知道这对你有帮助.您可以通过查看父节点 – 或父节点正在访问的对象类型来判断. 根据您的澄清添加 – 所以当你说 user => user.Email == email 您的意思是查找所有用户的电子邮件等于传入的参数 – 但该链接表达式意味着完全不同的东西. 你想说的是 Expression<Func<User,string,bool>> (user,email) => user.Email == email 这样,电子邮件现在将成为参数.如果你不喜欢,你可以做另外一件事. 第二个例子可以正常工作 – 不需要额外的参数,因为它们将是最佳的. t => t.Status != TaskStatus.Done && t.Status != TaskStatus.Failed 编辑:添加另一种方式: 因此,为了让代码正常工作,您必须做的一件事就是在lambda之外声明一个字符串电子邮件 – 这有点笨拙. 您可以通过将它们放在特定位置(如静态类)来更好地识别参数.然后当你通过Lambda时,你不必看一些可怕的cloture对象 – 而是一个很好的静态类. public static class Parameter { public static T Input<T>(string name) { return default(T); } } 然后你的代码看起来像这样: Expression<Func<User,bool>> exp = x => x.Email == Parameter.Input<String>("email"); 然后,您可以遍历树 – 当您调用参数静态类时,您可以查看类型和名称(在参数集合中),然后关闭…. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |