Constructor on Generic Class has Invalid Arguments

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?

Jon Skeet
people
quotationmark

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 :)

people

See more on this question at Stackoverflow