【问题标题】:Using lambda expressions and linq使用 lambda 表达式和 linq
【发布时间】:2010-05-20 01:36:46
【问题描述】:

所以我刚刚开始使用 linq 以及 lambda 表达式。我在尝试获取一些我想要的数据时遇到了一个小问题。此方法应返回 Jira 中打开或正在进行的所有项目的列表

这是代码

    public static List<string> getOpenIssuesListByProject(string _projectName)
    {
        JiraSoapServiceService jiraSoapService = new JiraSoapServiceService();
        string token = jiraSoapService.login(DEFAULT_UN, DEFAULT_PW);
        string[] keys = { getProjectKey(_projectName) };

        RemoteStatus[] statuses = jiraSoapService.getStatuses(token);
        var desiredStatuses = statuses.Where(x => x.name == "Open" || x.name == "In Progress")
            .Select(x=>x.id);

        RemoteIssue[] AllIssues = jiraSoapService.getIssuesFromTextSearchWithProject(token, keys, "", 99);
        IEnumerable<RemoteIssue> openIssues = AllIssues.Where(x=>
            {
                foreach (var v in desiredStatuses)
                {
                    if (x.status == v)
                        return true;
                    else
                        return false;
                }
                return false;
            });
        return openIssues.Select(x => x.key).ToList();
    }

目前这仅选择“打开”的问题,并且似乎跳过了“进行中”的问题。

我的问题:首先,为什么我只收到“开放”问题,其次是否有更好的方法来做到这一点?

我首先获取所有状态的原因是问题仅存储该状态 ID,因此我获取所有状态,获取匹配“Open”和“In Progress”的 ID,然后将这些 ID 号与问题状态字段。

【问题讨论】:

    标签: c# linq soap lambda jira


    【解决方案1】:
    IEnumerable<RemoteIssue> openIssues = AllIssues.Where(x=>
            {
                foreach (var v in desiredStatuses)
                {
                    if (x.status == v)
                        return true;
                }
                return false;
            });
    

    您的代码只是检查第一个状态并返回 false。您需要迭代所有状态并仅当它根本不在列表中时才返回 false。

    【讨论】:

    • 谢谢,我自己也想通了。看了 45 分钟,在我寻求帮助后 2 分钟我弄明白了:)
    【解决方案2】:

    嗯,你可以改变

    IEnumerable<RemoteIssue> openIssues = AllIssues.Where(x=>
    {
        foreach (var v in desiredStatuses)
        {
            if (x.status == v)
                return true;
            else
                return false;
        }
        return false;
    });
    

    IEnumerable<RemoteIssue> openIssues =
          AllIssues.Where(x=> desiredStatuses.Contains(x.status));
    

    至于为什么您没有同时获得这两种状态 - 斯蒂芬已经回答了这个问题。我上面的代码更改也将解决这个问题。

    【讨论】:

      【解决方案3】:

      您只获得一个状态的原因是,您总是在第一次检查后退出循环。如果第一项不匹配,则不再检查其他项。如果您删除 else 中的返回,它将起作用:

      foreach (var v in desiredStatuses) {
        if (x.status == v) {
          return true;
        }
      }
      return false;
      

      您应该确保实现所需状态的集合,这样您就不会在每次使用它时重新运行创建它的查询:

      var desiredStatuses =
        statuses
        .Where(x => x.name == "Open" || x.name == "In Progress")
        .Select(x=>x.id)
        .ToList();
      

      如果您只想检查几个状态,则无需提高效率。如果有很多状态,你可以将状态转化为HashSet,并使用它的Contains 方法,这比遍历项目要快得多。

      【讨论】:

      • 感谢您提供有关附加 ToList() 以防止每次查询的信息。我还是个新手,所以有点迷茫:)
      【解决方案4】:

      代码在我看来是正确的,尽管有一些方法可以用更少的编写代码来做到这一点......

      关于:

      目前这仅选择“打开”的问题,并且似乎跳过了“进行中”的问题。

      您能否确认两者都在 desiredStatuses 中?

      我还假设 RemoteIssue.status 属性确实是指状态的 id 而不是名称,因为这就是您要与之比较的?

      然后对于代码,根据 Martin Harris 的回答:我会使用 Contains 运算符而不是您的内部循环...

      【讨论】:

        【解决方案5】:

        改变这个:

        IEnumerable<RemoteIssue> openIssues = AllIssues.Where(x=>
                    {
                        foreach (var v in desiredStatuses)
                        {
                            if (x.status == v)
                                return true;
                            else
                                return false;
                        }
                        return false;
                    });
        

        到这里:

        IEnumerable<RemoteIssue> openIssues = AllIssues.Where(x=>
                    {
                        foreach (var v in desiredStatuses)
                        {
                            if (x.status == v)
                                return true;
                            //else
                                //return false;
                        }
                        return false;
                    });
        

        【讨论】:

          【解决方案6】:

          其他答案是正确的,但您可以使用直接 Lambda 而不是匿名委托更简洁地做到这一点。

          IEnumerable<RemoteIssue> openIssues = AllIssues.Where(x=> 
                  desiredStatuses.Contains(x.status)
          

          所以你的整个方法看起来像:

          public static List<string> getOpenIssuesListByProject(string _projectName)
          {
              JiraSoapServiceService jiraSoapService = new JiraSoapServiceService();
              string token = jiraSoapService.login(DEFAULT_UN, DEFAULT_PW);
              string[] keys = { getProjectKey(_projectName) };
          
              RemoteStatus[] statuses = jiraSoapService.getStatuses(token);
              var desiredStatuses = statuses.Where(x => x.name == "Open" || x.name == "In Progress")
                  .Select(x=>x.id);
          
              RemoteIssue[] AllIssues = jiraSoapService.getIssuesFromTextSearchWithProject(token, keys, "", 99);
              IEnumerable<RemoteIssue> openIssues = AllIssues.Where(x => desiredStatuses.Contains(x.status));
              return openIssues.Select(x => x.key).ToList();
          }
          

          这基本上会发出相当于 SQL“IN”子句的语句。所以你的声明如下:

          SELECT <RemoteIssue> FROM AllIssues AS x WHERE x.status IN <desiredStatuses>
          

          【讨论】:

            猜你喜欢
            • 2017-06-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-03-29
            • 2023-03-12
            • 1970-01-01
            相关资源
            最近更新 更多