I have the following function, which is basically a wrapper around something that makes a SQL call and reshapes the results:
public async IAsyncEnumerable ExecuteTable(string sql, IDictionary? parameters, [EnumeratorCancellation] CancellationToken cancellationToken)
{
var res = await ExecuteSQL(sql, parameters, cancellationToken).ConfigureAwait(false);
foreach (var row in res.Rows)
{
cancellationToken.ThrowIfCancellationRequested();
yield return RowConverter.ConvertRow(res.Columns, row);
}
}
You might notice that the enumeration is not really async, but this is an implementation of an interface, and it has to return IAsyncEnumerable.
I have unit tests covering this. The tests do this:
Successful execution, with results.
Successful execution, with no results.
Cancellation in ExecuteSQL (which throws OperationCanceledException).
Cancellation in the loop.
Non-cancellation exception in ExecuteSQL.
This is the question: the code coverage tool reports a branch not covered, on the very last closed bracket (the one that ends the method). Why?
Of course, this isn't a big deal; I would be okay with ignoring the issue - except that there is another method, which is absolutely identical except that it's not generic and returns IAsyncEnumerable
So, I'm curious as to what the difference could possibly be - why the compiler is apparently producing an unreachable branch, but only for generic and not for dynamic.
I've even tried debugging into the IL, but it's too difficult to follow. I've also created a non-generic and non-dynamic version just to see what happens; it reports as fully covered.