为什么AsObservable和AsEnumerable实现不同?

时间:2012-03-26 14:22:39

标签: c# linq ienumerable system.reactive

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

我理解这些方法对于在单个查询中更改monad非常有用(来自IQueryable =&gt; IEnumerable)。那么为什么实现会有所不同呢?

Observable版本更具防御性,因为您无法将其转换为某种已知类型(如果原始版本被实现为Subject<T>您永远无法将其转换为此类型)。那么为什么Enumerable版本没有做类似的事情呢?如果我的基础类型为List<T>,但通过IEnumerable<T>将其公开为AsEnumerable,则可以转回List<T>

请注意,这不是关于如何公开IEnumerable<T>而不能投射到基础版的问题,而是EnumerableObservable之间的实现在语义上不同的原因。

2 个答案:

答案 0 :(得分:15)

您的问题由文档解答,我建议您在提出此类问题时阅读。

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

正如the documentation所述:

  

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

如果您想要隐藏基础序列的实现,请使用sequence.Select(x=>x)ToListToArray,如果您不在乎您正在制作可变序列。

AsObservable的目的是隐藏底层集合的实现。正如the documentation所说:

  

Observable.AsObservable<TSource> ...隐藏可观察序列的身份。

由于这两种方法的目的完全不同,因此它们的实现完全不同。

答案 1 :(得分:10)

对于从基于表达式的查询切换到内存中查询的方面,AsEnumerable和AsObservable之间的关系是正确的。

同时,基于主题&lt; T&gt;暴露Rx序列。很常见,我们需要一种方法来隐藏它(否则用户可以转换为IObservable&lt; T&gt;并注入元素)。

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

请注意,我们在IQbservable上有一个名为AsObservable的扩展方法&lt; T&gt;同样。那个简单地完成了AsEnumerable所做的事情:它充当了编译器的提示,忘记了基于表达式的查询模式并切换到内存中查询。