【问题标题】:Change condition in LINQ by another condition通过另一个条件更改 LINQ 中的条件
【发布时间】:2015-07-20 19:05:57
【问题描述】:

我有这两条 LINQ 行,它们仅在一种情况下不同。

node.Image.Tag == nullnode.Image.Tag != null

if (treeSelectedNode.Image.Tag == null) 
  {
    radNode = tree.Find(node => node.Level == 0 && node.Image.Tag == null 
                           && node.Text.Equals(treeSelectedNode.Text));
  }
else 
  {
    radNode = tree.Find(node => node.Level == 0 && node.Image.Tag != null 
                           && node.Text.Equals(treeSelectedNode.Text));
  }

有没有办法在LINQ行之前创建条件然后使用它,以便我可以删除多余的行?

我知道我可以这样做:

radNode = treeSelectedNode.Image.Tag == null ? tree.Find(node => node.Level == 0 
            && node.Image.Tag == null && node.Text.Equals(treeSelectedNode.Text)) : 
                tree.Find(node => node.Level == 0 && node.Image.Tag != null 
                        && node.Text.Equals(treeSelectedNode.Text));

但这不是我想要的。

【问题讨论】:

  • 你能写:radNode = tree.Find(node => node.Level == 0 && node.Image.Tag == treeSelectedNode.Image.Tag && node.Text.Equals(treeSelectedNode.Text)); 吗?我问是因为我不确定你的代码逻辑,node.Image.Tag == treeSelectedNode.Image.Tag 是否正确
  • @KhanhTO No. 它不能比较两个对象的内容

标签: c# linq conditional-statements


【解决方案1】:

从技术上讲,您可以使用 Expression 构建这种查询,它需要额外的工作,这是一个简单的示例:

 private static Expression<Func<T, bool>> AndCombined<T>(Expression<Func<T, bool>> exp1, Expression<Func<T, bool>> exp2)
    {
        ParameterExpression p = exp1.Parameters.Single();
        return Expression.Lambda<Func<T, bool>>(Expression.And(exp1.Body, Expression.Invoke(exp2, p)), exp1.Parameters.Single());
    }

static void Main(string[] args)
    {
        var b = new List<int>() { 30, 15, 5 };

        Expression<Func<int, bool>> test1 = f => f > 10;
        Expression<Func<int, bool>> test2 = f => f < 20;
        var combinedAndQuery = AndCombined(test1, test2);

        var reuslt1 = b.Find(new Predicate<int>(combinedAndQuery.Compile()));
        Expression<Func<int, bool>> test3 = f => f < 40;


        var combinedAndQuery2 = AndCombined(test1, test3);

        var reuslt2 = b.Find(new Predicate<int>(combinedAndQuery2.Compile()));

}

【讨论】:

    【解决方案2】:

    检查条件node.Image.Tag == null的结果是否与treeSelected.Image.Tag == null的结果相同:

    radNode = tree.Find(node => node.Level == 0 && ((node.Image.Tag == null) == (treeSelectedNode.Image.Tag == null)) 
        && node.Text.Equals(treeSelectedNode.Text))
    

    更新

    部分解决@KhanTo 的性能问题:

    Boolean selectedImgTagIsNull  = treeSelected.Image.Tag == null;
    radNode = tree.Find(node => node.Level == 0 && ((node.Image.Tag == null) == selectedImgTagIsNull)
        && node.Text.Equals(treeSelectedNode.Text))
    

    但是,我怀疑即使对于我的原始代码,JIT 优化也很可能会产生相同的结果。

    【讨论】:

    • 这可能会降低性能,因为要对每个项目进行更多检查
    • @KhanhTO 检查被认为是 const-time 操作。我敢肯定,性能甚至不会引人注意。
    • 我倾向于同意@pwas,但我确实进行了更新以显示缓存 treeSelected.Image.Tag == null 检查。不过,我认为这也会在我原来的解决方案中得到优化。
    • 所以在我的情况下这是一个很好的解决方案。但我希望有更好的解决方案来匹配我们面临的每一种情况。
    【解决方案3】:

    也许 oneliner 适合你?

    radNode = tree.Find(node => node.Level == 0
                        && ((treeSelectedNode.Image.Tag == nulL 
                                && node.Image.Tag == null)
                            || (treeSelectedNode.Image.Tag != nulL 
                                && node.Image.Tag != null))
                        && node.Text.Equals(treeSelectedNode.Text));
    

    【讨论】:

      猜你喜欢
      • 2015-11-09
      • 2021-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多