为什么AsObservable和AsEnumerable的实现不同?

Enumerable.AsEnumerable<T>(this IEnumerable<T> source)只是返回source 。 然而, Observable.AsObservable<T>(this IObservable<T> source)返回一个订阅源的AnonymousObservable<T> ,而不是简单地返回源。

我知道这些方法对于在单个查询中更改monad非常有用(从IQueryable => IEnumerable)。 那么为什么这些实现有所不同?

Observable版本更具防御性,因为你不能将它转换成某种已知类型(如果它原来是作为Subject<T>实现的,你永远无法将它转换为此类)。 那么为什么Enumerable版本不能做类似的事情呢? 如果我的基础类型是一个List<T>但通过AsEnumerable将其暴露为IEnumerable<T> ,则可以将其转换回List<T>

请注意,这不是一个关于如何暴露IEnumerable<T>而不能转换为底层的问题,但为什么EnumerableObservable之间的实现在语义上是不同的。


您的问题由文档回答,我鼓励您在遇到此类问题时阅读。

AsEnumerable的目的是向编译器提示“请停止使用IQueryable并开始将其视为内存中的集合”。

正如文档所述:

除了将编译时类型的源从实现IEnumerable<T>的类型更改为IEnumerable<T>本身之外, AsEnumerable<TSource>(IEnumerable<TSource>)方法无效。 当序列实现IEnumerable<T>时, AsEnumerable<TSource>(IEnumerable<TSource>)可用于在查询实现之间进行选择,但也可以使用不同的公共查询方法。

如果你想隐藏一个底层序列的实现,使用sequence.Select(x=>x)ToListToArray如果你不关心你正在做一个可变序列。

AsObservable的目的是隐藏底层集合的实现。 正如文件所述:

Observable.AsObservable<TSource> ...隐藏可观察序列的标识。

由于这两种方法有完全不同的用途,它们具有完全不同的实现。


关于AsEnumerable和AsObservable之间的关系,从基于表达式树的查询切换到内存查询,您是对的。

同时,基于Subject <T>公开一个Rx序列是非常常见的,我们需要一种方法来隐藏它(否则用户可以投射到IObservable <T>并注入元素)。

很久以前,在Rx预发布的历史中,我们确实有一个单独的Hide方法,它只是一个Select(x => x)别名。 我们从来不喜欢它,并决定让我们偏离LINQ到Objects的精确镜像,并使AsObservable扮演Hide角色,也是基于那些认为这就是它开始的用户的基础。

但是请注意,我们在IQbservable <T>上也有一个名为AsObservable的扩展方法。 那个人简直就是AsEnumerable所做的:它作为编译器的提示,忘记基于表达式树的查询模式并切换到内存查询。

链接地址: http://www.djcxy.com/p/85057.html

上一篇: Why Are AsObservable and AsEnumerable Implemented Differently?

下一篇: C# 3.5 Covariance issue?