简体   繁体   中英

Using 'out' within lambdas when creating Tasks via Task Parallel Library

I have the following code that doesn't compile. I get the error

Cannot use ref or out parameter 'messageLockToken' inside an anonymous method, lambda expression, or query expression

I admit I'm new to Lambdas and am a bit confused about resolving this one. Does anyone know how I can express the logic below in a compiler acceptable manner?

public T Receive<T>(TimeSpan receiveTimeout, out Guid messageLockToken)
{
    // do work
}

public Task<T> ReceiveAsync<T>(TimeSpan receiveTimeout, out Guid messageLockToken)
{
    Task<T> sendQueueMsgTask = new Task<T>(() => Receive<T>(receiveTimeout, out messageLockToken));
    return sendQueueMsgTask;
}

First, your method wouldn't work even if it compiled. That's because when you use new Task() , you always have to call Start() on that Task (or, alternatively, use Task.Run() ).

Now, you can't use the out parameter here, because it doesn't make much sense. You want to return the Task from the method immediately, but that also means returning the Guid immediately. Which means there is no way for your call to Receive() to actually affect the value of the out parameter.

I think using a Tuple (as Rawling suggested) or a custom return type is the way to go here:

public Task<Tuple<T, Guid>> ReceiveAsync<T>(TimeSpan receiveTimeout)
{
    return Task.Run(
        () =>
        {
            Guid messageLockToken;
            var result = Receive<T>(receiveTimeout, out messageLockToken);
            return Tuple.Create(result, messageLockToken);
        });
}

This assumes you actually want to do this, see Stephen Toub's article Should I expose asynchronous wrappers for synchronous methods? for reasons why doing this is probably not a good idea.

Since you can't use an out parameter here, instead you could:

  • return a Tuple<T, Guid> (or use a custom generic class), or
  • pass an Action<Guid> rather than the out Guid (so rather than ReceiveAsync(ts, out myGuid) you'd call ReceiveAsync(ts, g => myGuid = g) )

(I don't think there's any way you can work around this to still expose an out parameter to the caller; an out parameter is supposed to be populated when the method returns, but this wouldn't be true in your case.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM