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>
而不能投射到基础版的问题,而是Enumerable
和Observable
之间的实现在语义上不同的原因。
答案 0 :(得分:15)
您的问题由文档解答,我建议您在提出此类问题时阅读。
AsEnumerable的目的是提示编译器“请停止使用IQueryable并开始将其视为内存中的集合”。
正如the documentation所述:
除了将源代码的编译时类型从实现
AsEnumerable<TSource>(IEnumerable<TSource>)
的类型更改为IEnumerable<T>
本身之外,IEnumerable<T>
方法无效。AsEnumerable<TSource>(IEnumerable<TSource>)
可用于在序列实现IEnumerable<T>
时选择查询实现,但也可以使用一组不同的公共查询方法。
如果您想要隐藏基础序列的实现,请使用sequence.Select(x=>x)
或ToList
或ToArray
,如果您不在乎您正在制作可变序列。
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所做的事情:它充当了编译器的提示,忘记了基于表达式的查询模式并切换到内存中查询。