2014-12-11 50 views
6

我剛纔注意到await關鍵字可以使用的Rx可觀察使用,例如:爲什麼可能等待Rx可觀察?

await Observable.Interval(TimeSpan.FromHours(1)); 

我敢肯定,它只能在配合使用的任務。

那是什麼使它成爲可能?觀察對象的知識是否被硬編碼到編譯器中?

回答

6

不,編譯器沒有IObservable<T>的專門知識。根據C#5規範的第7.7.7.1節,如果對象具有方法,或者存在名爲GetAwaiter的擴展方法,該擴展方法返回實現System.Runtime.CompilerServices.INotifyCompletion的類型,則可等待它。參見Steven Toub的文章Await anything

更具體地,從該規範

一個AWAIT表達的任務需要爲awaitable。表達awaitable如果下列之一成立:
- 是編譯時類型動態的
- 具有稱爲GetAwaiter與沒有參數和類型參數可訪問的實例或擴展方法,以及以下所有的返回類型A:
1. A實現接口System.Runtime.CompilerServices.INotifyCompletion(以下簡稱爲INotifyCompletion)
2. A具有可訪問的可讀實例屬性IsCompleted類型bool
3.有沒有參的可訪問實例方法調用getResult並沒有類型參數

注意如何,這是類似於如何foreach不需要IEnumerable<T>而只是一個返回兼容對象GetEnumerator方法。這種鴨子輸入是一種性能優化,它允許編譯器在沒有裝箱的情況下使用值類型。這可以用來避免性能敏感的代碼中不必要的分配。

+0

值得注意的是,當調用'OnCompleted'時,等待observable只返回最後一個值。如果序列中沒有任何值,則會拋出異常。 – 2014-12-11 04:07:24

7

我認爲這是因爲System.Reactive.LinqIObservable上定義了一個GetAwaiter擴展方法。正如@mike z解釋的那樣,允許您等待IObservable。下面是方法:

public static AsyncSubject<TSource> GetAwaiter<TSource>(this IObservable<TSource> source) 
{ 
    if (source == null) 
    { 
     throw new ArgumentNullException("source"); 
    } 
    return s_impl.GetAwaiter<TSource>(source); 
} 

返回類型AsyncSubject<T>實現INotifyCompletion並具有IsCompleted財產和GetResult方法。

public sealed class AsyncSubject<T> : ISubject<T>, ISubject<T, T>, IObserver<T>, IObservable<T>, IDisposable, INotifyCompletion 
{ 
    // Fields 
    private Exception _exception; 
    private readonly object _gate; 
    private bool _hasValue; 
    private bool _isDisposed; 
    private bool _isStopped; 
    private ImmutableList<IObserver<T>> _observers; 
    private T _value; 

    // Methods 
    public AsyncSubject(); 
    private void CheckDisposed(); 
    public void Dispose(); 
    public AsyncSubject<T> GetAwaiter(); 
    public T GetResult(); 
    public void OnCompleted(); 
    public void OnCompleted(Action continuation); 
    private void OnCompleted(Action continuation, bool originalContext); 
    public void OnError(Exception error); 
    public void OnNext(T value); 
    public IDisposable Subscribe(IObserver<T> observer); 

    // Properties 
    public bool HasObservers { get; } 
    public bool IsCompleted { get; }