Обнуляемый оператор в объявлении foreach с использованием C#7
Я смотрел на этот пример кода в C# 7.0
и я не был уверен в том, что происходило под капотом и производительности этой петли.
foreach (var c in text ?? throw new ArgumentNullException(nameof(text)))
{
...
}
Мои вопросы:
- Условный оператор получает удар один или несколько раз (на каждой итерации)?
- Новый синтаксис выглядит иначе, каковы преимущества этого?
2 ответа
Ты должен понимать foreach
внутренний код для понимания этого C#
особенность. Правая часть выражения в foreach
заявление должно реализовать IEnumerable(<T>)
интерфейс, и весь цикл, внутри, простой while
, что-то вроде этого:
// here can be NullReferenceException
var en = text.GetEnumerator();
while(en.MoveNext())
{
var c = en.Current;
{
...
}
}
Как видите, в этом коде есть точка NRE
может произойти, поэтому вам нужно проверить перечислимое перед целым циклом или Enumerable
класс расширений, вот так:
if (text.IsNullOrWhitespace())
{
throw new ArgumentNullException(nameof(text));
}
// while loop here or text.SomeLinqCodeHere()
Здесь есть несколько строк кода, которые на самом деле не являются ненужными, добавляя некоторую энтропию без реальной ценности. В случае простого foreach
это действительно основанное на мнении решение о стандартах кода, но реальная цель этой функции - связать ее с другими новыми вещами в C#7
, лайк ?.
оператор, как это:
int? length = customers?.Length ?? throw new ...;
Customer first = customers?[0] ?? throw new ...;
int? count = customers?[0]?.Orders?.Count() ?? throw new ...;
В таких случаях выдача исключения аналогична комментарию в конце строки кода:
int? length = customers?.Length; // should not be null
Customer first = customers?[0]; // should not be null
int? count = customers?[0]?.Orders?.Count(); // should not be null
но он добавляет некоторые строгие контрактные правила для вашего кода.
Что касается производительности для foreach
Цикл с такими выражениями, как уже было сказано, не страдает, так как получение перечислителя происходит только один раз, и до реального цикла.
В терминах "как работает foreach" условное утверждение будет рассчитываться только один раз.
Вы можете прочитать больше о том, как работают циклы foreach в следующих вопросах:
Как работают циклы foreach в C#?
Оценивает ли foreach массив на каждой итерации?
Спасибо Svek за объяснение, что это новая функция C# 7.0, которая будет выпущена после Visual Studio 2017 RC:
http://structuredsight.com/2016/09/01/c-7-additions-throw-expressions/
Я думаю, что "что такое выгода" - это своего рода вопрос, основанный на мнении.
На мой взгляд, это не приносит ничего хорошего и просто уродливо с точки зрения или читабельности кода.
Я бы рекомендовал использовать широко распространенную общепринятую практику:
if (text == null) // or string.IsNullOrEmpty for strings
throw new ArgumentNullException(nameof(text));
foreach (var c in text)
{
// ...
}
Возможно, через пару лет мы увидим использование исключения null-coalescing + throw, и оно станет новым стандартом:)