51 lines
1.7 KiB
Plaintext
51 lines
1.7 KiB
Plaintext
== Why is this an issue?
|
|
|
|
Because of the way ``++yield++`` methods are rewritten by the compiler (they become lazily evaluated state machines) any exceptions thrown during the parameters check will happen only when the collection is iterated over. That could happen far away from the source of the buggy code.
|
|
|
|
|
|
Therefore it is recommended to split the method into two: an outer method handling the validation (no longer lazy) and an inner (lazy) method to handle the iteration.
|
|
|
|
|
|
This rule raises an issue when a method throws any exception derived from ``++ArgumentException++`` and contains the ``++yield++`` keyword.
|
|
|
|
|
|
=== Noncompliant code example
|
|
|
|
[source,text]
|
|
----
|
|
public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) // Noncompliant
|
|
{
|
|
if (source == null) { throw new ArgumentNullException(nameof(source)); }
|
|
if (predicate == null) { throw new ArgumentNullException(nameof(predicate)); }
|
|
|
|
foreach (var element in source)
|
|
{
|
|
if (!predicate(element)) { break; }
|
|
yield return element;
|
|
}
|
|
}
|
|
----
|
|
|
|
|
|
=== Compliant solution
|
|
|
|
[source,text]
|
|
----
|
|
public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
|
|
{
|
|
if (source == null) { throw new ArgumentNullException(nameof(source)); }
|
|
if (predicate == null) { throw new ArgumentNullException(nameof(predicate)); }
|
|
return TakeWhileIterator<TSource>(source, predicate);
|
|
}
|
|
|
|
private static IEnumerable<TSource> TakeWhileIterator<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate)
|
|
{
|
|
foreach (TSource element in source)
|
|
{
|
|
if (!predicate(element)) break;
|
|
yield return element;
|
|
}
|
|
}
|
|
----
|
|
|