2017-01-04 14 views
7

Bạn có thể await anything trong C# 5+ miễn là loại có chức năng gọi là .GetAwaiter() trả về một đối tượng đặc biệt hoặc có phương pháp mở rộng thực hiện tương tự.Có thể chờ một chữ trống không?

Unity3d trong bản phát hành chính tiếp theo sẽ hỗ trợ async/await. Hiện tại trong Unity3d bạn có thể yield return null; bên trong một coroutine để đại diện cho "Chờ cho khung tiếp theo".

Tôi đã tự hỏi liệu có thể tạo phương pháp mở rộng cho phép bạn thực hiện await null; để có được hành vi tương tự hay không. Không có System.Null như có một số System.Void, vì vậy tôi không thể nghĩ loại nào được đặt trong phương thức mở rộng.

+0

Sẽ không chỉ là 'đang chờ Task.Yield() '? – spender

+0

@spender Có, toàn bộ phương thức mở rộng sẽ là 'public static YieldAwaitable GetAwaiter (this ???? temp) {return Task.Yield(); } 'Tôi chỉ không biết nếu có một cái gì đó có thể với phần' ???? '. –

+2

[Ẩn nghĩa đen không có loại] (https://ericlippert.com/2013/07/25/what-is-the-type-of-the-null-literal/) theo thông số kỹ thuật (kể từ 3.0), vì vậy tôi không nghĩ rằng có thể có bất cứ nơi nào để xác định một phương pháp mở rộng. – Blorgbeard

Trả lời

3

Không có cách nào để xác định một phương pháp khuyến nông trên một null nghĩa đen, vì một literal null has no type:

.. chúng tôi nhận ra rằng các loại rỗng là kỳ quái. Nó là một loại chỉ có một giá trị - hay là nó? Là giá trị của một null nullable int thực sự giống như giá trị của một chuỗi null? Và không giá trị của loại giá trị nullable đã có một loại, cụ thể là, các loại giá trị nullable?

Và:

Vì vậy chúng tôi loại bỏ tham chiếu đến vô dụng “loại null” trong đặc tả C# 3.0.

+0

Mặc dù đúng là chữ trống không có loại, nhưng đúng hơn là * tương thích * với nhiều loại, thực tế này không nhất thiết * khuyến khích * quyết định thiết kế không tìm kiếm các phương pháp mở rộng trên các chữ trống. Nói cách khác: giả sử tôi nói, không, chúng tôi đã sai, chúng ta nên nói rằng chữ rỗng có "loại chữ rỗng". Điều đó có thúc đẩy thay đổi quyết định thiết kế về các phương pháp khuyến nông không? Chắc là không. –

+1

Tôi đoán đó là sự thật - tôi đã sử dụng thiếu một loại null làm bằng chứng cho rằng, với cú pháp hiện tại cho các phương pháp mở rộng, không thể có cách nào để diễn tả "phương pháp mở rộng này áp dụng cho một null". Nhưng có lẽ đó không phải là lý do kín đáo. – Blorgbeard

+1

Chúng ta có thể dễ dàng nói rằng 'tĩnh Dù Foo (đối tượng này x) {...} ... null.Foo();' là hoàn toàn hợp pháp; 'null' được chuyển đổi thành' đối tượng', đó là tất cả những gì được yêu cầu. Bây giờ, bạn sẽ gặp phải các vấn đề với 'static Whatever Foo (T x)' này vì bây giờ 'null.Foo()' không thể suy ra một kiểu cho T, nhưng bất cứ điều gì, chúng ta đã có vấn đề với 'Foo (null) ; '. Không, 'null.Foo()' không được phép vì nó có mùi * khủng khiếp *; nếu bạn đang cố gắng để đặt một phương pháp mở rộng trên một chữ trống, bạn gần như chắc chắn làm điều gì đó sai trái. –

7

Bạn nói đúng rằng năng suất và chờ đợi có liên quan chặt chẽ. Cả hai đều là điểm trong một luồng công việc mà phương thức hiện tại bị tạm dừng, điều khiển được trả về cho người gọi và phương thức tiếp tục tại một điểm không xác định trong tương lai tại điểm mà sản lượng/chờ đợi xảy ra.

Nhưng chúng rất khác nhau về hành động của chúng trên các toán hạng của chúng. Trên thực tế, chúng thực tế là duals của nhau. Lợi nhuận cung cấp một giá trị mới khi yêu cầu bằng mã lặp lại chuỗi. An await chiết xuất một giá trị khi nó là sản xuất bởi nhiệm vụ thực hiện không đồng bộ.

Null là giá trị hoàn toàn hợp lệ, do đó, điều này có ý nghĩa cho một sản lượng để thu hút nó đến người gọi của nó. Nhưng null không phải là tác vụ hợp lệ và do đó, không có ý nghĩa gì khi chờ tìm cách trích xuất giá trị từ tác vụ.

Hiện tại trong Unity3d bạn có thể trả về null; bên trong một coroutine để đại diện cho "Chờ cho khung tiếp theo".

Trong luồng công việc không đồng bộ đang chờ đợi, tương tự của yield return null; chỉ là return null;. Điều đó có nghĩa là "kết thúc phần này của luồng công việc không đồng bộ bằng cách cung cấp tham chiếu null". Tại sao bạn không đơn giản trả về null nếu bạn có ý định tạo ra một tác vụ có kết quả là null?

Hãy để tôi đặt một cách khác có thể rõ ràng hơn.Rõ ràng điều này làm cho không có ý nghĩa:

foreach(var x in null) 
    Console.WriteLine(x); 

Đây là hệt vô nghĩa:

var x = await null; 
Console.WriteLine(x); 

Đây là những điều tương tự một cách logic. Foreach có nghĩa là "trích xuất một giá trị từ chuỗi miễn là giá trị có sẵn", nhưng null không phải là một chuỗi. Tương tự, "chờ đợi" có nghĩa là "trích xuất một giá trị từ tác vụ ngay sau khi một giá trị có sẵn", nhưng null không phải là một nhiệm vụ.

Đó là chìa khóa: tương tự không đồng bộ của await không phải là yield return, là foreach. Đó là cơ chế chiết xuất số T từ số IEnumerable<T> hoặc Task<T>. Thứ đặt Tvào loại monadic là yield return cho IEnumerable<T>return cho Task<T>.

+0

Để giải quyết đoạn cuối của bạn, đó là vì bạn thường sẽ có mã sau khi trả lại lợi nhuận.Ví dụ nếu bạn muốn một vòng lặp lặp lại một lần cho mỗi khung cho đến khi một điều kiện được đáp ứng, bạn có thể có 'while (_condition) {Foo(); lợi nhuận null; } 'Unity3d lạm dụng 'IEnumerator' để tạo ra async/await của riêng nó giống như hệ thống với Coroutines (Điều này đã được tạo trước khi async/await từng xuất hiện) –

+0

Nó có thể dễ dàng là' return return new WaitForSeconds (5); ' tương đương với 'await Task.Delay (TimeSpan.FromSeconds (5));'. –

+1

@ScottChamberlain: chờ đợi và lợi nhuận không chính xác kép vì nhiệm vụ và đếm được không chính xác kép. Một nhiệm vụ đại diện cho một giá trị thu được trong tương lai; một chuỗi đại diện cho nhiều giá trị thu được theo yêu cầu. Nhiệm vụ kép thực sự là func, và dual của enumerable là quan sát được. Vì vậy, nếu bạn muốn có một chuỗi * đẩy giá trị * thì bạn không muốn async chờ đợi; bạn muốn 'IObservable '; bạn muốn mở rộng phản ứng. –

Các vấn đề liên quan