Làm thế nào để Nhiệm vụ <int> trở thành một int?


116

Chúng tôi có phương pháp này:

async Task<int> AccessTheWebAsync()
{ 
    HttpClient client = new HttpClient();

   Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

   // You can do work here that doesn't rely on the string from GetStringAsync.
   DoIndependentWork();

   string urlContents = await getStringTask;
   //The thing is that this returns an int to a method that has a return type of Task<int>
   return urlContents.Length;
}

Có một chuyển đổi ngầm xảy ra giữa Task<int>int? Nếu không thì chuyện gì đang xảy ra? Làm thế nào nó được thực hiện để làm việc?


1
Hãy tiếp tục đọc . Tôi giả sử trình biên dịch sẽ chăm sóc điều đó dựa trên asynctừ khóa.
D Stanley

1
@Freeman, Hãy xem lời giải thích tuyệt vời này: stackoverflow.com/a/4047607/280758
qehgt

Câu trả lời:


171

Có một chuyển đổi ngầm xảy ra giữa Nhiệm vụ <> và int không?

Không. Đây chỉ là một phần của cách thức async/ awaitcông việc.

Bất kỳ phương thức nào được khai báo là asyncphải có kiểu trả về:

  • void (tránh nếu có thể)
  • Task (không có kết quả ngoài thông báo hoàn thành / thất bại)
  • Task<T>(cho kết quả hợp lý của loại Ttheo cách không đồng bộ)

Trình biên dịch thực hiện tất cả các gói thích hợp. Vấn đề là bạn quay trở lại không đồng bộurlContents.Length - bạn không thể làm cho phương thức trở lại int, vì phương thức thực tế sẽ trả về khi nó chạm vào awaitbiểu thức đầu tiên chưa hoàn thành. Vì vậy, thay vào đó, nó trả về một Task<int>cái sẽ hoàn thành khi chính phương thức async hoàn thành.

Lưu ý rằng awaitkhông điều ngược lại - nó unwraps một Task<T>đến một Tgiá trị, đó là cách dòng này hoạt động:

string urlContents = await getStringTask;

... nhưng tất nhiên nó sẽ hủy kết nối nó một cách không đồng bộ, trong khi chỉ cần sử dụng Resultsẽ chặn cho đến khi nhiệm vụ hoàn thành. ( awaitcó thể hủy bỏ các loại khác thực hiện mẫu đang chờ, nhưng Task<T>là loại bạn có thể sử dụng thường xuyên nhất.)

Gói / bỏ gói kép này là những gì cho phép async có thể kết hợp được. Ví dụ: tôi có thể viết một phương thức async khác gọi cho bạn và nhân đôi kết quả:

public async Task<int> AccessTheWebAndDoubleAsync()
{
    var task = AccessTheWebAsync();
    int result = await task;
    return result * 2;
}

(Hoặc đơn giản là return await AccessTheWebAsync() * 2;tất nhiên.)


3
có thể cung cấp bất kỳ chi tiết nào cho cách nó hoạt động dưới mui xe, chỉ tò mò.
Freeman

8
+1 Trả lời tốt như mọi khi. Và tại sao bạn lại viết chúng khá nhanh?!
Felix K.

9
+1: Mới bắt đầu tìm hiểu async/ awaitvà tôi thấy điều này cực kỳ không trực quan. IMO, nên có một từ khóa hoặc tương tự tại returnđể làm cho điều này rõ ràng, ví dụ return async result;(theo cùng một cách await result"mở khóa" Ttừ Tast<T>).
dav_i

2
@JonSkeet Nhưng nó không có ý nghĩa nếu không có sự await- với T foo = someTaskT;bạn muốn nhận được "Không thể ngầm chuyển đổi loại Task<T>để T" - trong cùng một cách tôi cho rằng nó sẽ có ý nghĩa hơn để có một từ khóa cho nghịch đảo (gói trong Task<T>). Tôi là tất cả để loại bỏ lông tơ nhưng trong trường hợp này tôi nghĩ rằng nó cung cấp một sự xáo trộn không cần thiết trong asynccác phương thức. (Rõ ràng vấn đề là phải tranh luận vì các quyền hạn đã được nói / mã hóa!)
dav_i

2
@dav_i: Bài tập không có ý nghĩa, nhưng phần còn lại thì có. Và có những trường hợp toàn bộ tuyên bố sẽ có ý nghĩa - mặc dù nó có thể không hữu ích. Cho rằng phương pháp đã được khai báo async, tôi nghĩ thế là đủ.
Jon Skeet

18

Không yêu cầu chuyển đổi Nhiệm vụ thành int. Đơn giản chỉ cần sử dụng Kết quả nhiệm vụ.

int taskResult = AccessTheWebAndDouble().Result;

public async Task<int> AccessTheWebAndDouble()
{
    int task = AccessTheWeb();
    return task;
}

Nó sẽ trả về giá trị nếu có nếu không nó trả về 0.


20
đó không phải là những gì tôi yêu cầu
Freeman

16
Điều này không trả lời câu hỏi. Nhưng quan trọng hơn, đây là lời khuyên rất tồi . Bạn gần như không bao giờ nên sử dụng Result; nó có thể gây ra bế tắc! Ví dụ, hãy xem xét quy trình công việc này: (1) Viết một ghi chú có nội dung "cắt cỏ". (2) Đợi cho bãi cỏ được cắt (3) Ăn bánh sandwich, (4) Làm bất cứ điều gì nó ghi trên ghi chú ". Với quy trình làm việc đó, bạn không bao giờ ăn bánh sandwich hoặc cắt cỏ, vì bước 2 là chờ đợi đồng bộ về một điều gì đó mà bạn sẽ làm trong tương lai . Nhưng đó là quy trình công việc mà bạn đang mô tả ở đây.
Eric Lippert

@EricLippert: Không rõ ví dụ của bạn. Bạn có thể giải thích làm thế nào Kết quả có thể giới thiệu bế tắc khi chờ đợi không?
CharithJ

3
Chờ đợi có nghĩa là làm một cái gì đó trong khi bạn chờ kết quả và điều gì đó có thể bao gồm thực hiện công việc để tính kết quả. Nhưng chờ đợi đồng bộ không làm gì trong khi bạn chờ đợi, điều đó có nghĩa là bạn có thể ngăn công việc được hoàn thành.
Eric Lippert

1
@EricLippert. Điều này sẽ có cùng một vấn đề? 'Nhiệm vụ.Run (() => AccessTheWebAndDouble ()). Kết quả;'
CharithJ
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.