加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 表达式树解析,变量最终成为常量

发布时间:2020-12-16 01:40:21 所属栏目:百科 来源:网络整理
导读:所以我正在开发一个需要解析表达式树的项目.我得到了大部分工作,但我遇到了一些问题. 我一直在关注表达树上的StackOverflow上的其他问题,但似乎无法找到我的问题的答案,所以这里. 我的问题是常量和变量之间的差异(或缺乏).让我从一个例子开始: user = user.
所以我正在开发一个需要解析表达式树的项目.我得到了大部分工作,但我遇到了一些问题.

我一直在关注表达树上的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);

在这里,我试图找到状态与“完成”和“失败”不同的所有任务.
这又是解析为存储过程.在第一个示例中,我的代码需要确定存储过程需要输入参数,即email变量的值.在第二个例子中,我不需要任何输入参数,我只需要创建用于选择状态不同于Done和Failed的任务的SQL.

再次感谢

解决方法

因此,从表达的角度来看,价值是一个常数.它不能被表达式改变.

你所拥有的是一个可能打开的闭包 – 即值可以在表达式的执行之间改变,但不能在它期间改变.所以这是一个“常数”.这是函数式编程和非函数式编程之间的范式差异.

考虑

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");

然后,您可以遍历树 – 当您调用参数静态类时,您可以查看类型和名称(在参数集合中),然后关闭….

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读