I'm looking to use the tips from this article to push the code coverage on a project of mine closer to 100%. Specifically the last section which outlines an idea for a workaround to methods I don't control or otherwise can't inject. The non-generic Task
version given in the article works like a charm, but I'm having a bit of trouble getting a generic Task<T>
version to work.
It's likely that I'm just missing something obvious.
My awaiter (with debug flags removed for brevity) is:
public class EnsureCodeCoverageAwaiter<T> : INotifyCompletion
{
private readonly TaskAwaiter<T> taskAwaiter;
private bool forceAsync;
public EnsureCodeCoverageAwaiter(Task<T> task)
{
this.taskAwaiter = task.GetAwaiter();
this.forceAsync = true;
}
public bool IsCompleted
{
get
{
if (this.forceAsync)
return false;
return this.taskAwaiter.IsCompleted;
}
}
public T GetResult()
{
this.forceAsync = false;
return this.taskAwaiter.GetResult();
}
public void OnCompleted(Action continuation)
{
this.forceAsync = false;
this.taskAwaiter.OnCompleted(continuation);
}
}
And my awaitable is:
public class EnsureCodeCoverageAwaitable<T>
{
private Task<T> _task;
public EnsureCodeCoverageAwaitable(Task<T> task)
{
_task = task;
}
public EnsureCodeCoverageAwaiter<T> GetAwaiter<T>()
{
return new EnsureCodeCoverageAwaiter<T>(_task);
}
}
The problem, according to the compiler, is on that last line in the GetAwaiter<T>
method. The compiler tells me:
The best overloaded method match for EnsureCodeCoverageAwaiter(Task<T>) has some invalid arguments
If I use Visual Studio's tooling to "generate constructor stub" from that same line, it generates a second constructor in EnsureCodeCoverageAwaiter
with the exact same signature as the existing one, and the error remains. (I can continue to use the same tooling to generate more and more identical constructor stubs.)
When I look at the intellisense while building that line of code, the constructor says it expects a Task<T>
and the variable I'm passing it claims to be of type Task<T>
.
Did I miss something about generics here?
This is the problem:
public EnsureCodeCoverageAwaiter<T> GetAwaiter<T>()
You don't want that to be a generic method introducing a new type parameter T
- you just want to use the type parameter of the type. So you want:
public EnsureCodeCoverageAwaiter<T> GetAwaiter()
The compiler should have given you a warning about this:
CS0693: Type parameter
'T'
has the same name as the type parameter from outer type'EnsureCoverageAwaitable<T>'
Always check compiler warnings :)
See more on this question at Stackoverflow