为什么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>,但将其公开为IEnumerable<T>AsEnumerable,则可以强制转换回List<T>

请注意,这不是关于如何在不能够强制转换到底层的情况下公开IEnumerable<T>的问题,而是为什么EnumerableObservable之间的实现在语义上不同的问题。

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

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

正如文件所述:

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

如果您想隐藏底层序列的实现,那么如果您不关心您正在生成可变序列,请使用sequence.Select(x=>x)ToListToArray

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

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

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

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

同时,基于受试者<T>是非常常见的,我们需要一种方法来隐藏它(否则用户可以强制转换为IObservable<T>并注入元素)。

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

不过,请注意,我们在IQobservable<T>也这一点也与AsEnumerable的作用很简单:它充当编译器的提示,让编译器忘记基于表达式树的查询模式,切换到内存中的查询。

相关内容

  • 没有找到相关文章

最新更新