0

I found this class in another answer Best way in .NET to manage queue of tasks on a separate (single) thread.

I wanted to try it out, but the syntax is a bit strange to me. Trying to just kick off a dummy task that returns a single int. I can't get this to compile, not sure what the syntax problem is.

        m_TaskQueue.Enqueue<int>(
                () => { return 1; }
            );

Compiler error:

Cannot convert lambda expression to delegate type System.Func<System.Threading.Tasks.Task<int>> because some of the return types in the block are not implicitly convertible to the delegate return type

Class from other answer:

public class TaskQueue
{
    private SemaphoreSlim semaphore;
    public TaskQueue()
    {
        semaphore = new SemaphoreSlim(1);
    }

    public async Task<T> Enqueue<T>(Func<Task<T>> taskGenerator)
    {
        await semaphore.WaitAsync();
        try
        {
            return await taskGenerator();
        }
        finally
        {
            semaphore.Release();
        }
    }
    public async Task Enqueue(Func<Task> taskGenerator)
    {
        await semaphore.WaitAsync();
        try
        {
            await taskGenerator();
        }
        finally
        {
            semaphore.Release();
        }
    }
}
Community
  • 1
  • 1
user17753
  • 3,083
  • 9
  • 35
  • 73

2 Answers2

7

To add to the other answers which suggest using Task.FromResult to create a task, you could also use an async lambda expression - this would be useful if you want to use await within the body of the lambda expression:

m_TaskQueue.Enqueue<int>(
    async () => { 
        await Task.Delay(1000); // For example
        return 1;
    }
);
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • So somehow adding an async/await to the lambda turns it from a `Func` to a `Func>`? – user17753 Jun 02 '15 at 14:42
  • @EhsanSajjad I think `async` lambdas is not workaround, but actually intended way to call this queuing code - there is really not much value to schedule synchronous operation to queue that will run it synchronously on the same thread in most cases. – Alexei Levenkov Jun 02 '15 at 14:46
  • @user17753: @user17753: Yup - just like adding `async` to a method declaration means that it has to have a return type of `Task` instead of `int` (but within the method, you still return an `int`...) Note that you don't *have* to `await` anything there, although you'll get a warning if you don't - it's the `async` contextual keyword which is important here. – Jon Skeet Jun 02 '15 at 14:49
  • Would something like `async () => { return await Task.Run( () => { return myInt; });` Make sense as well? Where I would do a bunch of stuff before returning myInt (perhaps slow I/O etc.). – user17753 Jun 02 '15 at 14:54
  • @user17753: Why would you do that? Instead of using `Task.Run`, just use asynchronous IO calls within the lambda expression. – Jon Skeet Jun 02 '15 at 15:06
  • OK I got it now. Thanks. Makes a lot more sense now. – user17753 Jun 02 '15 at 15:20
1

As the error is trying to tell you, you need a function that returns a Task<T>.

You can use Task.FromResult(1) to create one.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964