Tạo một tác vụ hoàn thành <T>


125

Tôi đang thực hiện một phương thức Task<Result> StartSomeTask()và tình cờ biết kết quả đã có trước khi phương thức được gọi. Làm cách nào để tạo một Tác vụ <T> đã hoàn thành?

Đây là những gì tôi đang làm:

private readonly Result theResult = new Result();

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

Có một giải pháp tốt hơn?


6
Lưu ý, các câu trả lời cho câu hỏi này cũng chỉ hoạt động tốt khi tạo một Tác vụ đơn giản (không <T>) vì Tác vụ <T> kế thừa từ Tác vụ.
Tim Lovell-Smith

Lưu ý rằng hôm nay có ValueTaskcác nhiệm vụ đã hoàn thành (nghĩa là đối với các giá trị bạn đã có để mã về cơ bản là đồng bộ), điều này sẽ giúp bạn tiết kiệm một khoản phân bổ.
nawfal

Câu trả lời:


111
private readonly Result theResult = new Result();

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

@DanielLobo bạn có thể nhận được câu trả lời nếu bạn giải thích sự phản đối của bạn là gì
2023861

1
Không phải nó nên là cái dưới đây đơn giản hơn và có nhiều phiếu bầu hơn sao? @ user2023861
Daniel Lobo

203

Khi nhắm mục tiêu .NET 4.5, bạn có thể sử dụng Task.FromResult:

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

Để tạo một tác vụ thất bại, sử dụng Task.FromException:

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

.NET 4.6 bổ sung Task.CompletedTasknếu bạn cần một cái chung Task.

public static Task CompletedTask { get; }

Giải pháp cho các phiên bản cũ hơn của .NET:

  • Khi nhắm mục tiêu .NET 4.0 với Gói mục tiêu Async (hoặc AsyncCTP), bạn có thể sử dụng TaskEx.FromResultthay thế.

  • Để có được không chung chung Tasktrước .NET 4.6, bạn có thể sử dụng thực tế Task<T>xuất phát từ Taskvà chỉ cần gọi Task.FromResult<object>(null)hoặc Task.FromResult(0).


13
Để trả về một tác vụ không chung chung, tốt hơn là sử dụng một cái gì đó như Task.FromResult (0). Sử dụng "null" làm tham số có thể gây nhầm lẫn cho trình biên dịch không thể xác định tham số chung.
Whyllee

Còn ngoại lệ thì sao? Các phương thức Async được biên dịch vào máy trạng thái để bắt ngoại lệ và lưu chúng trong Tác vụ được trả về. Điều này xảy ra ngay cả đối với việc thực thi mã trước khi chờ đợi đầu tiên. Phương thức trả về Task.FromResult có thể ném ngoại lệ trực tiếp.
Robert Važan

@ RobertVažan Một trường hợp cạnh thú vị. Có thể cho rằng, nếu bạn đang truy xuất kết quả đã biết của mình từ một phương thức và phương thức đó đưa ra các ngoại lệ thì có một lỗi cần phải sửa.
Gusdor

1
@ RobertVažan Bạn có thể dễ dàng viết FromExceptionphương thức của riêng mình , nó hoạt động như thế FromResultnhưng thay vào đó đại diện cho một nhiệm vụ bị lỗi. Một phương thức như vậy có thể đơn giản trả về điều đó cho các trường hợp lỗi của nó nếu điều quan trọng là ngoại lệ được thể hiện trong tác vụ kết quả.
Phục vụ

1
Task.FromException không có sẵn trong .NET 4.5 ... Tôi nghĩ rằng nó nên được chỉ định.
STiLeTT

12

Đối với các tác vụ không có giá trị trả về, .NET 4.6 đã thêm Task.CompletedTask .

Nó trả về một tác vụ đã có trong TaskStatus.RanToCompletion. Nó có thể trả về cùng một trường hợp mỗi lần, nhưng tài liệu cảnh báo bạn không nên dựa vào thực tế đó.


1

Nếu bạn đang sử dụng Rx, một giải pháp thay thế là Observable.Return (result) .ToTask ().


1

Gọi tác vụ. Khi tất cả không có bất kỳ tham số nào sẽ trả về một tác vụ đã hoàn thành.

Task task = Task.WhenAll();

trong khi điều này sẽ hoạt động, đó là một cách giải quyết tối nghĩa có thể khiến mọi người nhầm lẫn khi đọc mã vì nó ngụ ý chờ đợi các nhiệm vụ không tồn tại
Adrian Hristov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.