C # linq возможны рекомендации по множественному перечислению

1

Иногда я использую конструкции LINQ в своем источнике С#. Я использую VS 2010 с ReSharper. Теперь я получаю предупреждение "Возможное множественное перечисление IEnumerable" от ReSharper.

Я бы хотел реорганизовать его в соответствии с лучшими практиками. Вот кратко, что он делает:

IEnumerable<String> codesMatching = from c in codes where conditions select c;
String theCode = null;
if (codesMatching.Any())
{
  theCode = codesMatching.First();
}
if ((theCode == null) || (codesMatching.Count() != 1))
{
  throw new Exception("Matching code either not found or is not unique.");
}
// OK - do something with theCode.

Вопрос. Должен ли я сначала сохранить результат выражения LINQ в списке? (Я уверен, что он не вернется больше, чем несколько строк - скажем, максимум 10).

Любые намеки оценили.

Спасибо, Павел

Теги:
linq

3 ответа

3
Лучший ответ

Да, вам нужно сохранить результат как List\Array, а затем использовать его. В этом случае он не будет перечислять его пару раз.

В вашем случае, если вам нужно быть уверенным, что есть только один элемент, удовлетворяющий условию, вы можете использовать Single - если будет более одного элемента, удовлетворяющего условиям, он будет генерировать исключение. Если вообще не будет предметов, это тоже исключение.

И ваш код будет проще:

string theCode = (from c in codes where conditions select c).Single();

Но в этом случае вы не можете изменить текст исключения, или вам нужно обернуть его в собственный блок try\catch и перестроить его с помощью настраиваемого текста \exception

  • 4
    Но если есть ровно один элемент, и этот элемент равен null , Single не сгенерирует исключение, но код OP сработает. Обычно это не проблема, но стоит отметить, что это не обязательно замена.
  • 0
    Вы также можете прочитать ReadOnlyCollection <T>, если хотите только прочитать результаты вашего запроса.
Показать ещё 2 комментария
2

Поскольку вы хотите проверить, является ли ваше условие уникальным, вы можете попробовать это (и да, вы должны сохранить результат):

var codes = (from c in codes where conditions select c).Take(2).ToArray();
if (codes.Length != 1)
{
  throw new Exception("Matching code either not found or is not unique.");
}

var code = codes[0];
  • 1
    Зачем Take(2) ?
  • 2
    Я предполагаю, чтобы соответствовать, что есть больше чем один элемент, удовлетворяющий условиям
Показать ещё 2 комментария
1

Финализация, перечислимая с помощью .ToList()/.ToArray(), избавится от предупреждения, но для того, чтобы понять, лучше ли это, чем несколько перечислений или нет, будет зависеть от реализации codes и conditions. .Any() и .First() являются ленивыми примитивами и не будут выполняться за первым элементом, а .Count() может вообще не пострадать, поэтому преобразование в список может оказаться более расточительным, чем получение нового счетчика.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню