简体   繁体   English

F#中的自定义IEnumerator

[英]Custom IEnumerator in F#

More F# questions. 更多F#问题。 I have the implementation of a binary reader below. 我在下面有一个二进制阅读器的实现。 I want it to work like an enumerable sequence. 我希望它像一个可枚举的序列一样工作。 The code below gives me the following error and I have as usual no clue how to resolve it. 下面的代码给我以下错误,我一如既往地没有线索如何解决它。 I have ac# implementation where I had to implement two different overrides for .Current property. 我有ac#implementation,我必须为.Current属性实现两个不同的覆盖。 I guess I have to do the same here but not sure how. 我想我必须在这里做同样的事,但不知道如何。 As always, thanks a million in advance for your help. 一如既往,万分感谢您的帮助。

error FS0366: No implementation was given for Collections.IEnumerator.get_Current() : obj . 错误FS0366:没有为Collections.IEnumerator.get_Current() : obj Note that all interface members must be implemented and listed under an appropriate interface declaration, eg interface ... with member ... . 请注意,必须在适当的interface声明下实现并列出所有接口成员,例如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

As @Richard pointed out, you need to implement IEnumerator.Current . 正如@Richard所指出的,你需要实现IEnumerator.Current
Here's code in response to your question "how to do it". 这是响应您的问题“如何做”的代码。 This should work: 这应该工作:

A few notes: (thanks to @DaxFohl) 一些注意事项:(感谢@DaxFohl)

  • IEnumerator is in different namespace (see code). IEnumerator位于不同的命名空间中(参见代码)。
  • MoveNext and Reset are really members of IEnumerator , not IEnumerator<'t> , so that's where they should be implemented. MoveNextReset实际上是IEnumerator成员,而不是IEnumerator<'t> ,因此它们应该被实现。
  • Dispose , however, is on IEnumerator<'t> (surprise! :-) 然而, Dispose是在IEnumerator<'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() = ...

And in conclusion, I must add this: are you really sure you want to implement IEnumerator ? 最后,我必须补充一点:你真的确定要实现IEnumerator吗? This is a rather low-lever thing, easy to get wrong. 这是一个相当低调的事情,容易出错。 Why not use a sequence computation expression instead? 为什么不使用序列计算表达式呢?

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_
  }

IEnumerator<T> extends IEnumerator and IEnumerator has a Current property of type object . IEnumerator<T>扩展IEnumeratorIEnumerator具有object类型的Current属性。

You need to also implement IEnumerator.Current separately from IEnumerator<T>.Current . 您还需要与IEnumerator<T>.Current分别实现IEnumerator.Current

This version of the code compiles... as to does it really work.. will find out. 这个版本的代码编译...至于它真的有用..会发现。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM