Como alguns recursos se esgotam após uma leitura, pensei por que não combinar as verificações e as leituras, em vez da verificação separada tradicional, e depois ler.
Primeiro, temos um para a extensão inline check-for-null mais simples:
public static System.Collections.Generic.IEnumerable<T> ThrowOnNull<T>(this System.Collections.Generic.IEnumerable<T> source, string paramName = null) => source ?? throw new System.ArgumentNullException(paramName ?? nameof(source));
var first = source.ThrowOnNull().First();
Em seguida, temos o pouco mais envolvido (bem, pelo menos do jeito que escrevi), verifique se há uma extensão inline vazia e nula:
public static System.Collections.Generic.IEnumerable<T> ThrowOnNullOrEmpty<T>(this System.Collections.Generic.IEnumerable<T> source, string paramName = null)
{
using (var e = source.ThrowOnNull(paramName).GetEnumerator())
{
if (!e.MoveNext())
{
throw new System.ArgumentException(@"The sequence is empty.", paramName ?? nameof(source));
}
do
{
yield return e.Current;
}
while (e.MoveNext());
}
}
var first = source.ThrowOnNullOrEmpty().First();
É claro que você ainda pode ligar para os dois sem continuar a cadeia de chamadas. Além disso, incluí o paramName, para que o responsável pela chamada possa incluir um nome alternativo para o erro, se a "origem" não estiver sendo verificada, por exemplo, "nameof (target)".