สร้างงาน <T> ที่เสร็จสมบูรณ์


125

ฉันกำลังใช้วิธีการTask<Result> StartSomeTask()และบังเอิญรู้ผลลัพธ์อยู่แล้วก่อนที่เมธอดจะถูกเรียกใช้ ฉันจะสร้างงาน <T>ที่เสร็จสมบูรณ์แล้วได้อย่างไร?

นี่คือสิ่งที่ฉันกำลังทำอยู่:

private readonly Result theResult = new Result();

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

มีทางออกที่ดีกว่านี้หรือไม่?


6
หมายเหตุคำตอบสำหรับคำถามนี้ยังใช้ได้ดีกับการสร้าง Task ธรรมดา (ไม่ใช่ <T>) เนื่องจาก Task <T> สืบทอดมาจาก Task
Tim Lovell-Smith

โปรดทราบว่าวันนี้มีValueTaskงานที่เสร็จสมบูรณ์แล้ว (เช่นสำหรับค่าที่คุณมีอยู่แล้วเพื่อให้รหัสนั้นซิงโครนัสเป็นหลัก) ซึ่งจะช่วยให้คุณประหยัดการจัดสรร
nawfal

คำตอบ:


111
private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
    var taskSource = new TaskCompletionSource<Result>();
    taskSource.SetResult(theResult);
    return taskSource.Task;
}

@DanielLobo คุณอาจได้รับคำตอบถ้าคุณอธิบายว่าสิ่งที่คุณคัดค้านคืออะไร
user2023861

1
มันควรจะเป็นอันที่เรียบง่ายกว่าและมีคะแนนโหวตมากกว่านี้ไม่ใช่หรือ? @ user2023861
Daniel Lobo

203

เมื่อกำหนดเป้าหมาย. NET 4.5 คุณสามารถใช้Task.FromResult:

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

ในการสร้างงานที่ล้มเหลวให้ใช้Task.FromException:

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

.NET 4.6 เพิ่มTask.CompletedTaskหากคุณต้องการไฟล์Task.

public static Task CompletedTask { get; }

วิธีแก้ปัญหาสำหรับ. NET เวอร์ชันเก่า:

  • เมื่อกำหนดเป้าหมาย. NET 4.0 ด้วย Async Targetting Pack (หรือ AsyncCTP) คุณสามารถใช้TaskEx.FromResultแทนได้

  • หากต้องการรับที่ไม่ใช่แบบทั่วไปTaskก่อนหน้า. NET 4.6 คุณสามารถใช้ข้อเท็จจริงที่Task<T>มาจากTaskและเพียงแค่โทรTask.FromResult<object>(null)หรือTask.FromResult(0).


13
หากต้องการส่งคืนงานที่ไม่ใช่งานทั่วไปควรใช้บางอย่างเช่น Task.FromResult (0) การใช้ "null" เป็นพารามิเตอร์อาจทำให้คอมไพเลอร์สับสนซึ่งไม่สามารถระบุพารามิเตอร์ทั่วไปได้
Whyllee

แล้วข้อยกเว้นล่ะ? วิธีการ Async ถูกรวบรวมไว้ในเครื่องสถานะที่ตรวจจับข้อยกเว้นและบันทึกไว้ในงานที่ส่งคืน สิ่งนี้เกิดขึ้นแม้กระทั่งการเรียกใช้โค้ดก่อนรอครั้งแรก วิธีการส่งคืน Task.FromResult อาจทำให้เกิดข้อยกเว้นโดยตรง
Robert Važan

@ RobertVažanกรณีขอบที่น่าสนใจ หากคุณกำลังดึงผลลัพธ์ที่ทราบจากวิธีการและวิธีการนั้นแสดงข้อยกเว้นแสดงว่ามีข้อบกพร่องที่ต้องแก้ไข
Gusdor

1
@ RobertVažanคุณสามารถเขียนFromExceptionวิธีการของคุณเองได้อย่างง่ายดายซึ่งมีลักษณะเหมือนFromResultแต่แสดงถึงงานที่ผิดพลาด วิธีการดังกล่าวสามารถคืนค่านั้นสำหรับกรณีข้อผิดพลาดได้หากมีความสำคัญสำหรับการแสดงข้อยกเว้นในงานผลลัพธ์
Servy

1
Task.FromException ไม่มีใน. NET 4.5 ... ฉันคิดว่าควรระบุ
STiLeTT

12

สำหรับงานที่มีค่าตอบแทนไม่ .NET 4.6 ได้เพิ่มTask.CompletedTask

ส่งคืนงานที่มีอยู่แล้วใน TaskStatus.RanToCompletion มันอาจจะส่งคืนอินสแตนซ์เดิมทุกครั้ง แต่เอกสารจะเตือนให้คุณไม่ต้องพึ่งพาข้อเท็จจริงนั้น



1

การเรียกใช้ Task whenAll โดยไม่มีพารามิเตอร์ใด ๆ จะส่งคืนงานที่เสร็จสมบูรณ์

Task task = Task.WhenAll();

ในขณะที่วิธีนี้จะได้ผลมันเป็นวิธีแก้ปัญหาที่คลุมเครือซึ่งอาจทำให้ผู้คนสับสนเมื่ออ่านรหัสเนื่องจากแสดงถึงการรองานที่ไม่มีอยู่จริง
Adrian Hristov
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.