Подтвердить что ты не робот

С# Code Simplification Query: Null Container и Foreach Loop

У меня часто есть код, который выглядит примерно так:

if (itm != null)
{
    foreach (type x in itm.subItems())
    {
        //dostuff
    }
}
//do more stuff

В ситуациях, когда //do more stuff опущен, очень легко избежать дополнительного цикла foreach. Извлекая область с помощью соответствующей команды (в зависимости от того, что происходит, это обычно означает оператор return или continue statement).

Этот тип вещей имеет тенденцию приводить к коду стрелки. В настоящее время у меня есть несколько способов справиться с этим:

  • Используйте код типа itm = itm == null ? itm.subItems() : emptyArray
  • Разрешить код стрелки
  • Используйте goto
  • Использовать зловещие хаки (обертывание всего, если утверждение во всем, в объеме, а затем вырваться из него). На мой взгляд, злобные хаки в основном эквивалентны goto, за исключением более уродливых и трудных для чтения, поэтому я не считаю это допустимым решением.
  • Рефакторинг некоторых фрагментов в новые методы. На самом деле существует несколько случаев, когда это, вероятно, хорошее решение, но в основном это не подходит, поскольку нулевые ссылки в основном являются условиями ошибки из MS-функций.

Кто-нибудь хочет предложить ответ на то, какие подходы считаются предпочтительными?

4b9b3361

Ответ 1

Если вы используете С# 3, вы всегда можете написать метод расширения:

public static IEnumerable<SubItem> SafeSubItems(this ItemType item)
{
     return item == null ? Enumerable.Empty<SubItem> : source.SubItems();
}

Тогда просто напишите:

foreach (SubItem x in itm.SafeSubItems())
{
    // do stuff
}
// do more stuff

Главное, что методы расширения можно назвать даже "on" нулевыми ссылками.

Что было бы неплохо, это был бы оператор с нулевым безопасным разыменованием, поэтому мы могли бы написать:

// Not valid C# code!
foreach (SubItem x in itm?.SubItems() ?? Enumerable.Empty<SubItem>())
{
}

Или просто определите метод расширения EmptyIfNull на IEnumerable<T> и используйте

// Not valid C# code!
foreach (SubItem x in (itm?.SubItems()).EmptyIfNull())
{
}

Ответ 2

Вы можете использовать оператор

Ответ 3

Мне нравится меньше гнездящихся, для меня это лучше читается. Нет, пожалуйста, пожалуйста:)

Я держу методы короткими, поэтому обычно это возврат к этому сценарию.

if (itm == null) return;
foreach (type x in itm.subItems())
{
   //dostuff
}

Если требуется больше материала, это простые операторы и могут быть выполнены перед foreach, вы можете:

if (itm == null)
{
   //do more stuff 
   return;
}
foreach (type x in itm.subItems())
{
   //dostuff
}

Если это не так, скорее всего, метод слишком длинный, и некоторые из них будут удалены в любом случае. Возможно:

if( itm != null ) SomeActionOnSubItems(itm.subItems);
// do more stuff (can be some method calls depending on level of abstraction).

Ответ 4

Лично я бы, вероятно, оставил структуру так, как у вас есть.

Первый вариант (itm = itm == null? itm.subItems(): emptyArray) кажется менее неприятным, чем другие, но мне все же нравится ваше оригинальное качество.

Проблема в том, что с другой точки зрения разработчика все остальное сделает ваш код менее очевидным. Если в коллекции есть foreach, я ожидаю, что коллекция (по крайней мере, обычно) содержит элементы, содержащиеся в ней. Если сбор может быть пустым, это не будет очевидно для других людей без комментариев (которые занимают больше времени, чем проверка if).

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