【问题标题】:Use ExpressionVisitor to change 'obj == value' to 'obj.Equals(value)'使用 ExpressionVisitor 将 'obj == value' 更改为 'obj.Equals(value)'
【发布时间】:2016-04-03 21:29:59
【问题描述】:

我正在尝试将一个对象与一个随机值(可能是一个 ID)和 ObjectKey 或什至与同一个对象进行比较。简而言之,我想将一个对象与任何东西进行比较,而不仅仅是同一类型。

为此,我覆盖了对象的 Equals() 和 GetHashCode(),它按预期工作。但是我注意到当我通过 'obj == value' 搜索时,Linq 不会调用这些方法。

如果我将查询更改为“obj.Equals(value)”,则应调用 Equals() 方法。但这不是我需要的。

此外,我尝试重载 '==' 和 '!=' 运算符,但是当我通过接口搜索时,这些重载不会被调用。

最后,我不能只手动更改所有查询,因为将来有人可能会在任何地方使用“==”,从而破坏代码。

所以我来到 ExpressionVisitor。我注意到我可以为我的 Linq 查询重写表达式,但我有点无能为力。我尝试了一些我找到的示例,但我遇到了一些错误。

最后,这是我通过 ExpressionVisitor 需要的:

替换这个: var objects = ctx.Where(obj => obj == value);

对此: var objects = ctx.Where(obj => obj.Equals(value));

有可能吗?

【问题讨论】:

    标签: linq expressionvisitor


    【解决方案1】:

    这是可能的。您可以编写一个代理查询提供程序,在重写表达式后将查询传递给真正的提供程序。

    您还可以使用“LinqKit”与AsExpandable 重写器一起使用的方法。这种方法要简单得多,但需要将这些调用插入到每个查询中。

    您还可以使用 Roslyn 对源代码执行一次性重构。这样做的缺点是源代码在那些 Equals 调用中看起来不太好。

    我没有必要的时间来草拟这些解决方案,因为它们的工作量很大。对于AsExpandable,您可以在网上找到工作代码。我相信也有编写 LINQ 提供程序的教程。

    【讨论】:

      【解决方案2】:

      是的。找到了:

      class Program
      {
          static void Main(string[] args)
          {
              //the sample:
              Expression<Func<string, bool>> expr = name => name == "AA" || name.Length > 0 || name != "b";
              Console.WriteLine(expr);
              EqualsModifier treeModifier = new EqualsModifier();
              Expression modifiedExpr = treeModifier.Modify((Expression)expr);
              Console.WriteLine(modifiedExpr);
              Console.ReadLine();
          }
      }
      //the ExpressionVisitor
      public class EqualsModifier : ExpressionVisitor
      {
          public Expression Modify(Expression expression)
          {
              return Visit(expression);
          }
          protected override Expression VisitBinary(BinaryExpression b)
          {
              if (b.NodeType == ExpressionType.Equal)
              {
                  Expression left = this.Visit(b.Left);
                  Expression right = this.Visit(b.Right);
                  MethodInfo equalsMethod = typeof(string).GetMethod("Equals", new[] { typeof(string) });
                  return Expression.Call(left, equalsMethod, right);
              }
              else if (b.NodeType == ExpressionType.NotEqual)
              {
                  Expression left = this.Visit(b.Left);
                  Expression right = this.Visit(b.Right);
                  MethodInfo equalsMethod = typeof(string).GetMethod("Equals", new[] { typeof(string) });
                  return Expression.Not(Expression.Call(left, equalsMethod, right));
              }
              return base.VisitBinary(b);
          }
      }
      

      这些都输出到:

      原文: name => (((name == "AA") OrElse (name.Length

      转换: name => ((name.Equals("AA") OrElse (name.Length

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-13
        • 2020-01-21
        • 2022-11-24
        • 2019-08-08
        • 1970-01-01
        相关资源
        最近更新 更多