Почему в F #, я могу это сделать ...F #: Downcast след в IEnumerator
let s = seq { for i in 0 .. 4095 do yield i } :?> IEnumerator
... но это бросает System.InvalidCastException
?
let s = Seq.init 4095 (fun i -> i) :?> IEnumerator
Почему в F #, я могу это сделать ...F #: Downcast след в IEnumerator
let s = seq { for i in 0 .. 4095 do yield i } :?> IEnumerator
... но это бросает System.InvalidCastException
?
let s = Seq.init 4095 (fun i -> i) :?> IEnumerator
Выражение последовательность создает объект, который реализует IEnumerable<T>
и IEnumerator<T>
let s = seq { for i in 0 .. 4095 do yield i }
printfn "%b" (s :? IEnumerable<int>) // true
printfn "%b" (s :? IEnumerator<int>) // true
Но Seq.init
не:
let s = Seq.init 4095 (fun i -> i)
printfn "%b" (s :? IEnumerable<int>) // true
printfn "%b" (s :? IEnumerator<int>) // false
Вы можете реорганизовать код, чтобы использовать IEnumerable<T>
вместо IEnumerator
так как конструкции производят IEnumerable<T>
.
В качестве альтернативы, если вы действительно хотите IEnumerator
, вы могли бы просто назвать GetEnumerator
, чтобы возвращать Enumerator
из Enumerable
:
let s = (Seq.init 4095 (fun i -> i)).GetEnumerator()
printfn "%b" (s :? IEnumerable<int>) // false
printfn "%b" (s :? IEnumerator<int>) // true
Данг, украл мой ответ. Ну, часть этого ... Не знаю, что выражения последовательности не производят совсем то же самое, что и их копии модуля Seq. – Jwosty
Если посмотреть на the specification, вы секвенирования выражение преобразуется в:
Seq.collect (fun pat -> Seq.singleton(pat)) (0 .. 4095)
если вы посмотрите на источник для определения Seq.collect
:
let collect f sources = map f sources |> concat
, и если вы посмотрите на определение для concat
это:
let concat sources =
checkNonNull "sources" sources
mkConcatSeq sources
mkConcatSeq
определяется как:
let mkConcatSeq (sources: seq<'U :> seq<'T>>) =
mkSeq (fun() -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>)
, так что вы можете увидеть, что возвращаемый последовательность реализует IEnumerator<'T>
и поэтому IEnumerator
.
Теперь Seq.init
определяется как:
let init count f =
if count < 0 then invalidArg "count" (SR.GetString(SR.inputMustBeNonNegative))
mkSeq (fun() -> IEnumerator.upto (Some (count-1)) f)
и mkSeq
определяется как:
let mkSeq f =
{ new IEnumerable<'U> with
member x.GetEnumerator() = f()
interface IEnumerable with
member x.GetEnumerator() = (f() :> IEnumerator) }
так это только реализует IEnumerable<'T>
и не IEnumerator
.
Вы уверены, что не хотите IEnumerable, а не IEnumerator? – ildjarn
Я пишу сопрограмму для Единства. Должен быть IEnumerator. – MiloDC