Làm thế nào về việc không có một từ khóa?
Tôi muốn trình biên dịch nhận ra rằng, hầu hết thời gian, khi tôi gọi một phương thức không đồng bộ, tôi muốn kết quả của nó.
Document doc = DownloadDocumentAsync();
Đó là nó. Lý do mọi người gặp khó khăn khi nghĩ ra một từ khóa cho việc này là vì nó giống như có một từ khóa để "làm điều bạn làm nếu mọi thứ hoàn toàn bình thường". Đó phải là mặc định, không yêu cầu một từ khóa.
Cập nhật
Ban đầu tôi đề nghị trình biên dịch nên thông minh với suy luận kiểu để tìm ra phải làm gì. Nghĩ thêm về điều này, tôi vẫn giữ cách triển khai hiện có trong CTP, nhưng hãy thực hiện một vài bổ sung nhỏ cho nó, để giảm bớt các trường hợp bạn cần sử dụng await
từ khóa một cách rõ ràng.
Chúng tôi phát minh ra một thuộc tính : [AutoAwait]
. Điều này chỉ có thể được áp dụng cho các phương pháp. Một cách để áp dụng điều này vào phương pháp của bạn là đánh dấu nó async
. Nhưng bạn cũng có thể làm điều đó bằng tay, ví dụ:
[AutoAwait]
public Task<Document> DownloadDocumentAsync()
Sau đó, bên trong bất kỳ async
phương thức nào , trình biên dịch sẽ cho rằng bạn muốn chờ cuộc gọi đến DownloadDocumentAsync
, vì vậy bạn không cần chỉ định nó. Bất kỳ cuộc gọi đến phương thức đó sẽ tự động chờ đợi nó.
Document doc = DownloadDocumentAsync();
Bây giờ, nếu bạn muốn "thông minh" và có được Task<Document>
, bạn sử dụng một toán tử start
, chỉ có thể xuất hiện trước một cuộc gọi phương thức:
Task<Document> task = start DownloadDocumentAsync();
Tôi gọn gàng. Bây giờ một cuộc gọi phương thức đơn giản có nghĩa là những gì nó thường có nghĩa là: chờ cho phương thức hoàn thành. Và start
chỉ ra điều gì đó khác biệt: đừng chờ đợi.
Đối với mã xuất hiện bên ngoài một async
phương thức, cách duy nhất bạn được phép gọi một [AutoAwait]
phương thức là bằng cách thêm tiền tố vào đó start
. Điều này buộc bạn phải viết mã có cùng ý nghĩa bất kể nó có xuất hiện trong một async
phương thức hay không.
Rồi tôi bắt đầu tham lam! :)
Đầu tiên, tôi muốn async
áp dụng các phương thức giao diện:
interface IThing
{
async int GetCount();
}
Về cơ bản, điều đó có nghĩa là phương thức thực hiện phải trả về Task<int>
hoặc một cái gì đó tương thích await
và người gọi phương thức sẽ có [AutoAwait]
hành vi.
Ngoài ra khi tôi thực hiện phương pháp trên, tôi muốn có thể viết:
async int GetCount()
Vì vậy, tôi không phải đề cập đến Task<int>
như là loại trả lại.
Ngoài ra, tôi muốn async
áp dụng cho các loại đại biểu (mà suy cho cùng, giống như các giao diện với một phương thức). Vì thế:
public async delegate TResult AsyncFunc<TResult>();
Một async
đại biểu đã - bạn đoán nó - [AutoAwait]
hành vi. Từ một async
phương thức bạn có thể gọi nó và nó sẽ tự động được chỉnh sửa await
(trừ khi bạn chọn chỉ start
nó). Và nếu bạn nói:
AsyncFunc<Document> getDoc = DownloadDocumentAsync;
Điều đó chỉ hoạt động. Đây không phải là một cuộc gọi phương thức. Chưa có nhiệm vụ nào được bắt đầu - async delegate
đây không phải là một nhiệm vụ. Đó là một nhà máy để thực hiện các nhiệm vụ. Bạn có thể nói:
Document doc = getDoc();
Và điều đó sẽ bắt đầu một nhiệm vụ và chờ đợi nó kết thúc và cung cấp cho bạn kết quả. Hoặc bạn có thể nói:
Task<Document> t = start getDoc();
Vì vậy, một nơi trong đó "đường ống dẫn nước" bị rò rỉ là nếu bạn muốn tạo một đại biểu cho một async
phương thức, bạn phải biết sử dụng một async delegate
loại. Vì vậy, thay vì Func
bạn phải nói AsyncFunc
, và như vậy. Mặc dù một ngày nào đó loại điều đó có thể được sửa chữa bằng suy luận loại được cải thiện.
Một câu hỏi khác là điều gì sẽ xảy ra nếu bạn nói bắt đầu với một phương thức thông thường (không đồng bộ). Rõ ràng một lỗi biên dịch sẽ là lựa chọn an toàn. Nhưng có những khả năng khác.