Использование лямбда-выражений и linq - PullRequest
0 голосов
/ 19 мая 2010

Итак, я только начал работать с linq, а также с использованием лямбда-выражений. Я столкнулся с небольшой ошибкой, пытаясь получить некоторые данные, которые я хочу. Этот метод должен возвращать список всех проектов, которые открыты или выполняются из 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 с выдает поле состояния.

Ответы [ 6 ]

3 голосов
/ 19 мая 2010
IEnumerable<RemoteIssue> openIssues = AllIssues.Where(x=>
        {
            foreach (var v in desiredStatuses)
            {
                if (x.status == v)
                    return true;
            }
            return false;
        });

Код, который вы имели, проверял только первое состояние и возвращал false. Вам нужно перебрать все состояния и вернуть false только в том случае, если его вообще нет в списке.

2 голосов
/ 19 мая 2010

Ну, вы можете изменить

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

Что касается того, почему вы не получаете оба статуса - Стефан ответил на это. Мое изменение кода выше тоже исправит эту проблему.

1 голос
/ 19 мая 2010

Причина, по которой вы получаете только один статус, заключается в том, что вы всегда возвращаетесь из цикла после первой проверки. Если первый элемент не совпадает, больше элементов не проверяется. Если вы удалите возврат в 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, который намного быстрее, чем циклический просмотр предметов.

0 голосов
/ 19 мая 2010

Другие ответы верны, но вы можете сделать это немного более лаконично, используя прямую лямбду вместо анонимного делегата.

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>
0 голосов
/ 19 мая 2010

Изменить это:

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;
            });
0 голосов
/ 19 мая 2010

Код выглядит мне правильно, хотя есть способы сделать это с помощью менее написанного кода ...

Относительно:

Сейчас это только те проблемы, которые "Открыты", и, кажется, пропускают те, которые "В процессе".

Можете ли вы подтвердить, что оба находятся в нужных статусах?

Также я предполагаю, что свойство RemoteIssue.status действительно ссылается на идентификатор статуса, а не на имя, поскольку вы сравниваете его с этим?

Тогда для кода, согласно ответу Мартина Харриса: я бы использовал оператор Contains, а не ваш внутренний цикл ...

...