Как получить, если элемент существует в IEnumerable, используя Linq

Как бы вы реорганизовали этот метод?

private bool IsTermExist(string word)
 {
 var query = from term in m_xdoc.Descendants("Term")
 where term.Attribute("Name").Value.ToUpper().Contains(word.ToUpper())
 select term;

 return query.Any();
 }
3 ответа

Я бы, вероятно, использовал перегрузку Any которая принимает предикат:

private bool TermExists(string word)
{
 return m_xdoc.Descendants("Term")
 .Any(term => term.Attribute("Name").Value
 .IndexOf(word, StringComparison.OrdinalIgnoreCase) >= 0);
}

Заметки:

  • Использование ToUpper для нечувствительности к регистру обычно чревато (например, из-за поведения на турецком языке, что является неожиданным для большинства разработчиков); использование перегрузки IndexOf которое принимает StringComparison является предпочтительным. (Там аналогичная перегрузка для Equals.)
  • Если бы мы собирались сравнить с word.ToUpper(), мы могли бы извлечь его так, чтобы word.ToUpper() выполнялся только один раз, а не один раз за элемент Term. (Микро-оптимизация в сторону, я думаю, что это вообще хорошая идея, чтобы сначала извлечь итерационно-инвариантные части запроса. Но не ожидайте согласованности на этом фронте :)
  • Этот код по-прежнему будет работать для элементов Term без атрибутов Name. Это может быть или не быть тем, что вы хотите.


Я бы, наверное, написал следующее:

private static bool MatchesName(XElement el, string name)
{
 var attr = el.Attribute("Name");
 return attr.Value.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0;
}

private bool TermExists(string word)
{
 return m_xdoc.Descendants("Term").Any(e => MatchesName(e, word));
}

Трудно сказать, где отделить вспомогательный метод, не видя другого кода.


Если вы хотите вернуть первый соответствующий элемент, а не как метод, который возвращает элемент или null если не найден:

private XElement? GetTerm(string word)
{
 var query = from term in m_xdoc.Descendants("Term")
 where term.Attribute("Name").Value.ToUpper().Contains(word.ToUpper())
 select term;

 return query.FirstOrDefault();
}

licensed under cc by-sa 3.0 with attribution.