问题
More F# questions. 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 a c# implementation where I had to implement two different overrides for .Current
property. 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
. Note that all interface members must be implemented and listed under an appropriateinterface
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
回答1:
As @Richard pointed out, you need to implement IEnumerator.Current
.
Here's code in response to your question "how to do it". This should work:
A few notes: (thanks to @DaxFohl)
IEnumerator
is in different namespace (see code).MoveNext
andReset
are really members ofIEnumerator
, notIEnumerator<'t>
, so that's where they should be implemented.Dispose
, however, is onIEnumerator<'t>
(surprise! :-)
-
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
? 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_
}
回答2:
IEnumerator<T>
extends IEnumerator and IEnumerator
has a Current
property of type object
.
You need to also implement IEnumerator.Current separately from IEnumerator<T>.Current
.
回答3:
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
来源:https://stackoverflow.com/questions/30128320/custom-ienumerator-in-f