F# 中的自定义 IEnumerator

Custom IEnumerator in F#

更多 F# 问题。我在下面有一个二进制 reader 的实现。我希望它像可枚举序列一样工作。下面的代码给了我以下错误,我像往常一样不知道如何解决它。我有一个 c# 实现,其中我必须为 .Current 属性 实现两个不同的覆盖。我想我必须在这里做同样的事情,但不确定如何做。一如既往,提前一百万感谢您的帮助。

error FS0366: No implementation was given for Collections.IEnumerator.get_Current() : obj. Note that all interface members must be implemented and listed under an appropriate interface declaration, e.g. interface ... with member ....

namespace persisitence
open System.Collections.Generic
open System
open System.IO
type BinaryPersistenceIn<'T>(fn: string, serializer: ('T * BinaryReader) -> unit) as this =
    let stream_ = File.Open(fn, FileMode.Open, FileAccess.Read)
    let reader_ = new BinaryReader(stream_)
    [<DefaultValue>] val mutable current_ : 'T

    let eof() =
         stream_.Position = stream_.Length


    interface IEnumerator<'T> with

        member this.MoveNext() = 
            let mutable ret = eof()

            if stream_.CanRead && ret then
                serializer(this.current_, reader_)

            ret

        member this.Current
            with get() = this.current_ 

        member this.Dispose() =
            stream_.Close()
            reader_.Close()

        member this.Reset() = 
            stream_.Seek((int64) 0., SeekOrigin.Begin) |> ignore

IEnumerator<T> 扩展 IEnumerator 并且 IEnumerator 有一个 Current 属性 类型 object.

您还需要与 IEnumerator<T>.Current 分开实施 IEnumerator.Current

正如@Richard 指出的那样,您需要实施 IEnumerator.Current.
这是回答您的问题 "how to do it" 的代码。这应该有效:

一些注意事项:(感谢@DaxFohl)

  • IEnumerator 在不同的命名空间中(见代码)。
  • MoveNextReset 实际上是 IEnumerator 的成员,而不是 IEnumerator<'t>,所以它们应该在那里实现。
  • 然而,
  • DisposeIEnumerator<'t> 上(惊喜!:-)

-

type BinaryPersistenceIn<'T>(fn: string, serializer: ('T * BinaryReader) -> unit) as this =
    ...    

    interface IEnumerator<'T> with
        ...
        member this.Current
            with get() = this.current_ 

    interface System.Collections.IEnumerator with
        member this.Current
            with get() = this.current_ :> obj
        member this.MoveNext() = ...
        member this.Reset() = ...

最后,我必须补充一点:您真的确定要实施IEnumerator吗?这是一个相当低级的事情,很容易出错。为什么不改用序列计算表达式?

let binaryPersistenceSeq (fn: string) (serializer: BinaryReader -> 'T) = 
  seq {
    use stream_ = File.Open(fn, FileMode.Open, FileAccess.Read)
    use reader_ = new BinaryReader(stream_)

    let eof() = stream_.Position = stream_.Length

    while not eof() do
       if stream_.CanRead then
          yield serializer reader_
  }

这个版本的代码编译...至于它是否真的有效...会发现。

type BinaryPersistenceIn<'T>(fn: string, serializer: ('T * BinaryReader) -> unit) =
let stream_ = File.Open(fn, FileMode.Open, FileAccess.Read)
let reader_ = new BinaryReader(stream_)
[<DefaultValue>] val mutable current_ : 'T

let eof() =
     stream_.Position = stream_.Length


interface IEnumerator<'T> with

    member this.MoveNext() = 
        let mutable ret = eof()

        if stream_.CanRead && ret then
            serializer(this.current_, reader_)

        ret

    member this.Current
        with get() = this.current_ 

    member this.Dispose() =
        stream_.Close()
        reader_.Close()

    member this.Reset() = 
        stream_.Seek((int64) 0., SeekOrigin.Begin) |> ignore

    member this.Current
        with get() = this.current_ :> obj