ChatGPT解决这个技术问题 Extra ChatGPT

Create a completed Task

I want to create a completed Task (not Task<T>). Is there something built into .NET to do this?

A related question: Create a completed Task<T>

It seems like the answer I'm getting from everyone is that using a garbage value like this is the correct way. That there isn't a way to do this without the garbage value is disappointing -- oh well. What problems do you think this has? If you cache a single Task then your entire program takes up one extra bit of memory. That's nothing. Also, one could create a completed task without doing that, it just wouldn't be any better.
Oh my disappointment has nothing to do with having to use extra memory. It's just that garbage values anywhere in code are not elegant.
Note that today there's ValueTask for completed tasks (i.e. for values you already have so that code is essentially synchronous), which will save you an allocation.

i
i3arnon

The newest version of .Net (v4.6) is adding just that, a built-in Task.CompletedTask:

Task completedTask = Task.CompletedTask;

That property is implemented as a no-lock singleton so you would almost always be using the same completed task.


Just checked the latest VS 14 CTP and created a 4.5.3 project, Task.CompletedTask is still internal.
2. Either you haven't downloaded the latest CTP (which is 4 and linked to from that site) or you haven't specified version 4.5.3. Here's what's on my machine. @PeterRitchie
I created a VM from the Visual Studio 14 image on Azure.
I am working on Mac OS X with mono 5.4.1.7 and I get this same error. How can I fix this?
S
Servy

Task<T> is implicitly convertable to Task, so just get a completed Task<T> (with any T and any value) and use that. You can use something like this to hide the fact that an actual result is there, somewhere.

private static Task completedTask = Task.FromResult(false);
public static Task CompletedTask()
{
    return completedTask;
}

Note that since we aren't exposing the result, and the task is always completed, we can cache a single task and reuse it.

If you're using .NET 4.0 and don't have FromResult then you can create your own using TaskCompletionSource:

public static Task<T> FromResult<T>(T value)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(value);
    return tcs.Task;
}

If you're using 4.0, you can add the Microsoft.Bcl.Async library to get TaskEx.FromResult, as well as other handy things like WhenAll
@Servy What does it change from FromResult(false) and FromResult(true)?
@FrancescoB. If you're ever looking at the result, then it change the boolean value of the result. If you're ignoring the result, then what the result is is irrelevant.
R
Richiban

My preferred method for doing this is to call Task.WhenAll() with no arguments. The MSDN documentation states that "If the supplied array/enumerable contains no tasks, the returned task will immediately transition to a RanToCompletion state before it's returned to the caller.". That sounds like what you want.

Update: I found the source over at Microsoft's Reference Source; there you can see that Task.WhenAll contains the following:

return (tasks.Length == 0) ? // take shortcut if there are no tasks upon which to wait
            Task.CompletedTask :
            new WhenAllPromise(tasks);

So Task.CompletedTask is indeed internal, but it is exposed by calling WhenAll() with no arguments.


while it DOES feel kind of hacky, it has support from the docs, so I dunno, I kinda like it!
For me and my .NET 4.5.2 constrained code it's elegant enough. Thanks!
g
gzak

I would use Task.Delay(0). Internally, it returns a cached instance of a completed Task<T>. This is exactly what the current answer suggest doing anyway, only now you don't have to cache an instance yourself, nor do you have any inelegant garbage values in your code.

You might be thinking you can use Task.Yield() instead, but it turns out the result of Task.Yield() is not a subtype of Task, whereas the result of Task.Delay(0) is. That's one of the subtle differences between the two.


R
Reed Copsey

You can use Task.FromResult (in .NET 4.5) to return a completed Task<T>.

If you need a non-generic Task, you can always use Task.FromResult(0) or similar, since Task<T> is a subclass of Task.


I
Icen

For .Net 4.6 and above use

return Task.CompletedTask;

For lower version you can use

return new Task(() => { });

For the pre 4.6 approach, careful! You need to Start the task or it will never complete! How about using return Task.Delay(0); instead?
L
Lessneek

You can use Nito.AsyncEx.TaskConstants.Completed from a great library AsyncEx from Stephen Cleary.


link to Nito.AsyncEx.TaskConstants.Completed source file is dead
@harlam357 fixed.
D
Dorus

How about:

#pragma warning disable 1998
    public async Task emptyTask() {
    }
#pragma warning restore 1998

You can leave out the warning suppression if you don't mind it.


I believe that marking a method async still creates the whole state machine apparatus even if you don't use it, so returning an empty task is more efficient for low-resource scenarios.