我刚刚注意到await
关键字可以与Rx Observable一起使用,例如:
await Observable.Interval(TimeSpan.FromHours(1));
我非常确定它只能与任务一起使用。
那是什么让它成为可能?是否将可观察的知识硬编码到编译器中?
答案 0 :(得分:7)
不,编译器对IObservable<T>
没有特别的了解。根据C#5规范的7.7.7.1节,如果对象有方法或者在名为GetAwaiter
的范围内有一个返回实现System.Runtime.CompilerServices.INotifyCompletion
的类型的扩展方法,则可以等待它。请参阅Steven Toub的文章Await anything。
更具体地说,来自规范
等待表达式的任务必须是等待的。如果下列之一成立,表达式 t 等待:
- t 是编译时类型动态
- t 有一个名为GetAwaiter的可访问实例或扩展方法,没有参数,没有类型参数,以及一个返回类型A,以下所有内容都保持:
1.实现接口System.Runtime.CompilerServices.INotifyCompletion(以下简称为INotifyCompletion)
2. A具有可访问的,可读的实例属性IsCompleted类型为bool
3. A有一个可访问的实例方法GetResult,没有参数,也没有类型参数
请注意这与foreach
不需要IEnumerable<T>
的方式类似,而只是一个返回兼容对象的GetEnumerator方法。这种鸭子类型是一种性能优化,它允许编译器使用值类型而无需装箱。这可用于避免性能敏感代码中不必要的分配。
答案 1 :(得分:7)
我认为这是因为System.Reactive.Linq
在GetAwaiter
上定义了IObservable
扩展方法。正如@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; }