Buat Tugas yang selesai

197

Saya ingin membuat yang selesai Task(tidak Task<T>). Apakah ada sesuatu yang dibangun dalam. NET untuk melakukan ini?

Pertanyaan terkait: Buat Tugas selesai <T>

Perisai Timothy
sumber
2
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.Menurut Anda masalah apa yang terjadi? Jika Anda men-cache satu Taskmaka seluruh program Anda memakan satu bit ekstra memori. Bukan apa - apa . Juga, seseorang dapat membuat tugas yang selesai tanpa melakukan itu, itu tidak akan lebih baik.
Servy
10
Oh kekecewaan saya tidak ada hubungannya dengan harus menggunakan memori tambahan. Hanya saja nilai-nilai sampah di mana saja dalam kode tidak elegan.
Timothy Shields
1
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:

247

Versi terbaru .Net (v4.6) menambahkan hanya itu, Task.CompletedTask bawaan :

Task completedTask = Task.CompletedTask;

Properti itu diimplementasikan sebagai singleton tanpa kunci sehingga Anda hampir selalu menggunakan tugas yang sama.

i3arnon
sumber
1
Baru saja memeriksa VS 14 CTP terbaru dan membuat proyek 4.5.3, Task.CompletedTaskmasih internal.
Peter Ritchie
1
2. Entah Anda belum mengunduh CTP terbaru (yang 4 dan ditautkan dari situs itu) atau Anda belum menentukan versi 4.5.3. Inilah yang ada di mesin saya . @PeterRitchie
i3arnon
Saya membuat VM dari gambar Visual Studio 14 di Azure.
Peter Ritchie
1
@PeterRitchie Dari template Azure VS14CTP4
i3arnon
Saya bekerja pada Mac OS X dengan mono 5.4.1.7 dan saya mendapatkan kesalahan yang sama. Bagaimana saya bisa memperbaikinya?
Khaled Annajar
153

Task<T>secara implisit dapat dikonversi Task, jadi dapatkan yang lengkap Task<T>(dengan Tnilai apa saja dan apa saja) dan gunakan itu. Anda dapat menggunakan sesuatu seperti ini untuk menyembunyikan fakta bahwa hasil aktual ada di sana, di suatu tempat.

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

Perhatikan bahwa karena kami tidak mengekspos hasilnya, dan tugas selalu selesai, kami dapat men-cache satu tugas dan menggunakannya kembali.

Jika Anda menggunakan .NET 4.0 dan tidak memilikinya, FromResultAnda dapat membuatnya sendiri menggunakan TaskCompletionSource:

public static Task<T> FromResult<T>(T value)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(value);
    return tcs.Task;
}
Melayani
sumber
8
Jika Anda menggunakan 4.0, Anda dapat menambahkan perpustakaan Microsoft.Bcl.Async untuk mendapatkan TaskEx.FromResult, serta hal-hal praktis lainnya seperti WhenAll
Carl
@Ervy Apa yang diubahnya dari FromResult (false) dan FromResult (true)?
Francesco Bonizzi
3
@FrancescoB. Jika Anda pernah melihat hasilnya, maka itu mengubah nilai boolean dari hasilnya. Jika Anda mengabaikan hasilnya, maka apa hasilnya tidak relevan.
Servy
66

Metode pilihan saya untuk melakukan ini adalah menelepon Task.WhenAll()tanpa argumen. The MSDN dokumentasi menyatakan bahwa "Jika disediakan array / enumerable tidak mengandung tugas, tugas kembali akan segera transisi ke keadaan RanToCompletion sebelum itu kembali ke pemanggil.". Kedengarannya seperti yang Anda inginkan.

Pembaruan: Saya menemukan sumbernya di Sumber Referensi Microsoft ; di sana Anda dapat melihat bahwa Tugas. Ketika Semua berisi yang berikut:

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

Jadi Task.CompletedTask memang internal, tetapi diekspos dengan memanggil WhenAll () tanpa argumen.

Richiban
sumber
9
sementara itu Rasanya agak berantakan, ia mendapat dukungan dari para dokter, jadi saya tidak tahu, saya agak menyukainya!
Sara
2
Bagi saya dan kode terbatas .NET 4.5.2 saya cukup elegan. Terima kasih!
Stas Ivanov
36

Saya akan menggunakan Task.Delay(0). Secara internal, ia mengembalikan contoh cache yang selesai Task<T>. Ini persis seperti apa yang disarankan oleh jawaban saat ini, hanya sekarang Anda tidak perlu membuat cache contoh sendiri, juga tidak memiliki nilai sampah yang salah dalam kode Anda.

Anda mungkin berpikir Anda dapat menggunakan Task.Yield()sebagai gantinya, tapi ternyata hasil Task.Yield()ini bukan subtipe dari Task, sedangkan hasil Task.Delay(0)adalah. Itulah salah satu perbedaan halus antara keduanya.

gzak
sumber
30

Anda dapat menggunakan Task.FromResult (dalam .NET 4.5) untuk mengembalikan yang sudah selesai Task<T>.

Jika Anda memerlukan non-generik Task, Anda selalu dapat menggunakan Task.FromResult(0)atau serupa, karena Task<T>merupakan subkelas dari Task.

Reed Copsey
sumber
11

Untuk .Net 4.6 dan penggunaan di atas

return Task.CompletedTask;

Untuk versi yang lebih rendah, Anda dapat menggunakan

return new Task(() => { });
Icen
sumber
3
Untuk pendekatan pra 4.6, hati-hati! Anda harus Memulai tugas atau tidak akan pernah selesai! Bagaimana kalau menggunakan return Task.Delay(0);saja?
Miquel
0

Bagaimana tentang:

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

Anda dapat meninggalkan penindasan peringatan jika Anda tidak keberatan.

Dorus
sumber
Saya percaya bahwa menandai metode asyncmasih menciptakan peralatan mesin seluruh negara bahkan jika Anda tidak menggunakannya, jadi mengembalikan tugas kosong lebih efisien untuk skenario sumber daya rendah.
Calvin Fisher