You should understand foreach
inner code for understanding this C#
feature. A right part of expression in foreach
statement must implement IEnumerable(<T>)
interface, and whole loop is, internally, a simple while
, something like this:
// here can be NullReferenceException
var en = text.GetEnumerator();
while(en.MoveNext())
{
var c = en.Current;
{
...
}
}
As you can see, there is a point in this code the NRE
can occur, so you need to check the enumerable before entire loop or Enumerable
extensions class, like this:
if (text.IsNullOrWhitespace())
{
throw new ArgumentNullException(nameof(text));
}
// while loop here or text.SomeLinqCodeHere()
There are some lines of code here which aren't really unnecessary, adding some entropy without real value. In case of simple foreach
it really opinion-based decision about code standards, but the real purpose of this feature is chaining it with other new things in C#7
, like ?.
operator, like this:
int? length = customers?.Length ?? throw new ...;
Customer first = customers?[0] ?? throw new ...;
int? count = customers?[0]?.Orders?.Count() ?? throw new ...;
In such cases throwing the exception is similar to comment at the end of the line of code:
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
but it adds some strict contract-like rules for your code.
As for the performance for foreach
loop with such expressions, as already said, it doesn't suffer as getting the enumerator occurs only once, and before the real loop.