|
1
23
或者更准确地说,您不应该将其用作Scheme解释器工作的基本基础。为什么不制作一个简单的不可变链表呢?
请注意
回答你的问题:
IEnumerable可以在世界任何地方获取数据。下面是一个从控制台读取行的示例:
这有两个问题:第一,一个
另一个例子:
对于这两个例子,您接受的“变通方法”没有多大用处,因为它只会耗尽可用内存或永远挂断。但这些都是序列的完美例子。 要理解C和F序列,您需要查看Haskell中的列表,而不是Scheme中的列表。 如果您认为无限量的内容是一种误导,那么从套接字读取字节怎么样:
如果有一些字节被发送到套接字,这将不是一个无限序列。然而,为它编写克隆将是非常困难的。编译器将如何生成IEnumerable实现来自动执行该操作?
一旦创建了克隆,这两个实例现在就必须在它们共享的缓冲区系统中工作。这是可能的,但在实践中并不需要——这并不是设计这些序列的目的。您纯粹是“功能性”地对待它们,就像对待值一样,递归地对它们应用过滤器,而不是“强制性地”记住序列中的位置。它比低级的要干净一点
我想最简单的答案是看看里面
Abelson and Sussman
尤其是
the part about streams
.
|
|
|
2
4
作为一种解决方法,您可以轻松地为执行克隆的IEnumerator创建一个扩展方法。只需从枚举器创建一个列表,并将元素用作成员。 但是,您将失去枚举器的流式处理功能—因为您是新的“克隆”,这将导致第一个枚举器完全计算。 |
|
|
3
3
如果可以放弃原始枚举数,即不再使用它,则可以实现一个“克隆”函数,将原始枚举数作为一个或多个枚举数的源。 换句话说,您可以构建如下内容:
它们可以在内部共享原始枚举数和链接列表,以跟踪枚举值。
当然,这里的问题是,如果其中一个枚举数远远领先于另一个枚举数,它仍然需要大量内存。 这是源代码。如果使用Subversion,则可以下载Visual Studio 2008解决方案文件,其中包含一个包含以下代码的类库,以及一个单独的单元测试项目。
存储库:
http://vkarlsen.serveftp.com:81/svnStackOverflow/SO847655
请注意,此代码根本不是线程安全的。
|
|
|
4
1
这将使用反射创建新实例,然后在新实例上设置值。我还发现C#Depth中的这一章非常有用。 Iterator block implementation details: auto-generated state machines
这个答案也用于以下问题 Is it possible to clone an IEnumerable instance, saving a copy of the iteration state? |
|
|
5
1
“clonable”枚举数的目的主要是保存迭代位置,并在以后返回到该位置。这意味着,迭代容器必须提供比
如果您的容器不支持随机访问,并且只能向前迭代(如一个定向链表),那么它必须至少提供获取下一个元素的能力,引用上一个元素或您可以在迭代器中保存的某个“迭代状态”。因此,界面可以如下所示:
注意迭代器是 不变的 ,它不能“向前移动”,我们只能要求iterable容器为我们提供一个指向下一个位置的新迭代器。这样做的好处是,您可以根据需要将迭代器存储在任何位置,例如,有一个迭代器堆栈,并在需要时返回到以前保存的位置。您可以通过指定一个变量来保存当前位置,以备将来使用,就像使用整数索引一样。
这个
这个
这几乎是一样的。确定下一个状态的逻辑只是从容器实现转移到迭代器 实施请注意,迭代器仍然是 不变的 |
|
|
6
0
为什么不将此作为扩展方法:
这将基本上创建并返回一个新的枚举数,而无需完全计算原始枚举数。 编辑:是的,我看错了。Paul是正确的,这只适用于IEnumerable。 |
|
|
7
0
|
|
|
8
-2
已经有了一种创建新枚举数的方法——与创建第一个枚举数的方法相同:IEnumerable.GetEnumerator。我不知道你为什么需要另一个机制来做同样的事情。 并本着 DRY principle ,我很好奇为什么您希望创建新IEnumerator实例的责任在您的enumerable和enumerator类中重复。您将强制枚举器保持超出所需的额外状态。 例如,想象一个链表的枚举器。对于IEnumerable的基本实现,该类只需要保留对当前节点的引用。但为了支持您的克隆,它还需要保留一个列表头的引用,否则它就没有用了*。当您只需转到源(IEnumerable)并获取另一个枚举数时,为什么还要向枚举数添加额外的状态? 为什么要将需要测试的代码路径数量增加一倍?每次你用一种新的方法来制造一个物体,你就增加了复杂性。
|