Buat Tugas yang selesai <T>

125

Saya menerapkan metode Task<Result> StartSomeTask()dan kebetulan mengetahui hasilnya sebelum metode dipanggil. Bagaimana cara membuat Tugas <T> yang sudah selesai?

Inilah yang sedang saya lakukan:

private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
    var task = new Task<Result>(() => theResult);
    task.RunSynchronously(CurrentThreadTaskScheduler.CurrentThread);
    return task;
}

Apakah ada solusi yang lebih baik?

dtb
sumber
6
Catatan, jawaban untuk pertanyaan ini juga berfungsi dengan baik untuk membuat Tugas biasa (bukan <T>) karena Tugas <T> mewarisi dari Tugas.
Tim Lovell-Smith
Perhatikan bahwa hari ini ada ValueTaskuntuk tugas yang diselesaikan (yaitu untuk nilai yang sudah Anda miliki sehingga kode pada dasarnya sinkron), yang akan menghemat alokasi.
nawfal

Jawaban:

111
private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
    var taskSource = new TaskCompletionSource<Result>();
    taskSource.SetResult(theResult);
    return taskSource.Task;
}
QrystaL
sumber
@DanielLobo Anda mungkin mendapatkan jawaban jika Anda menjelaskan apa keberatan Anda
user2023861
1
Bukankah seharusnya yang di bawah ini lebih sederhana dan dengan lebih banyak suara? @ user2023861
Daniel Lobo
203

Saat menargetkan .NET 4.5 Anda dapat menggunakan Task.FromResult:

public static Task<TResult> FromResult<TResult>(TResult result);

Untuk membuat tugas yang gagal, gunakan Task.FromException:

public static Task FromException(Exception exception);
public static Task<TResult> FromException<TResult>(Exception exception);

.NET 4.6 menambahkan Task.CompletedTaskjika Anda memerlukan non generik Task.

public static Task CompletedTask { get; }

Penanganan masalah untuk versi .NET yang lebih lama:

  • Saat menargetkan .NET 4.0 dengan Async Targetting Pack (atau AsyncCTP), Anda dapat menggunakannya TaskEx.FromResult.

  • Untuk mendapatkan non-generik Tasksebelum. NET 4.6, Anda dapat menggunakan fakta yang Task<T>berasal dari Taskdan hanya menelepon Task.FromResult<object>(null)atau Task.FromResult(0).

CodesInChaos
sumber
13
Untuk mengembalikan tugas yang tidak umum, lebih baik menggunakan sesuatu seperti Task.FromResult (0). Menggunakan "null" sebagai parameter dapat membingungkan compiler yang tidak dapat menentukan parameter generik.
Whyllee
Bagaimana dengan pengecualian? Metode Async dikompilasi ke dalam mesin negara yang menangkap pengecualian dan menyimpannya dalam Tugas yang dikembalikan. Ini terjadi bahkan untuk mengeksekusi kode sebelum menunggu terlebih dahulu. Metode mengembalikan Task.FromResult mungkin melempar pengecualian secara langsung.
Robert Važan
@ RobertVažan Kasing tepi yang menarik. Dapat diperdebatkan, jika Anda mengambil hasil yang diketahui dari suatu metode dan metode itu melempar pengecualian maka ada cacat yang perlu diperbaiki.
Gusdor
1
@ RobertVažan Anda dapat dengan mudah menulis FromExceptionmetode Anda sendiri , yang berperilaku seperti FromResulttetapi merupakan tugas yang salah. Metode seperti itu dapat dengan mudah mengembalikannya untuk kasus kesalahannya jika penting agar pengecualian ditampilkan dalam tugas yang dihasilkan.
Servy
1
Task.FromException tidak tersedia di .NET 4.5 ... Saya pikir itu harus ditentukan.
STiLeTT
12

Untuk tugas tanpa nilai balik, .NET 4.6 telah menambahkan Task.CompletedTask .

Ini mengembalikan tugas yang sudah ada di TaskStatus.RanToCompletion. Mungkin mengembalikan contoh yang sama setiap kali, tetapi dokumentasi memperingatkan Anda untuk tidak mengandalkan fakta itu.

Daryl
sumber
1

Jika Anda menggunakan Rx, alternatifnya adalah Observable.Return (hasil) .ToTask ().

Niall Connaughton
sumber
1

Memanggil Tugas. Ketika semua tanpa parameter akan mengembalikan tugas yang selesai.

Task task = Task.WhenAll();
zumalifeguard
sumber
sementara ini akan berhasil, ini merupakan solusi yang tidak jelas yang mungkin membingungkan orang ketika membaca kode karena itu menyiratkan menunggu tugas yang tidak ada
Adrian Hristov