我正试图从我简化的一个例子中吸取以下行为的教训:
let groupedEnum (input: 'a seq) =
using (input.GetEnumerator()) (fun en ->
Seq.unfold(fun _ ->
if en.MoveNext() then
Some(en.Current, ())
else None) ()
)
//WORKS
let c = groupedEnum ("11111122334569999" |> List.ofSeq ) |> List.ofSeq
//BOOM !! System.NullReferenceException
let c = groupedEnum ("11111122334569999" ) |> List.ofSeq编辑:,这只是一个玩具例子,用来说明一种行为,而不是被遵循。很少有充分的理由直接操作枚举器。
发布于 2012-11-22 12:35:05
一旦lambda函数返回,using函数就会处理枚举数。但是,lambda函数使用Seq.unfold创建一个延迟序列,在从groupedEnum返回序列之后,延迟序列访问枚举数。
您可以完全评估using内部的整个序列(通过在其中添加List.ofSeq ),也可以在到达生成序列的末尾时调用Dispose:
let groupedEnum (input: 'a seq) =
let en = input.GetEnumerator()
Seq.unfold(fun _ ->
if en.MoveNext() then
Some(en.Current, ())
else
en.Dispose()
None)在这种情况下,异常处理变得非常困难,但我想其中一种方法是将主体封装在try .. with中,并在发生异常时调用Dispose (然后返回None)。
如果您使用序列表达式,那么use的含义就会发生变化,并且它会在到达序列结束后(而不是在返回延迟序列时)自动处理枚举数。因此,使用序列表达式可能是一个更好的选择,因为辛苦的工作是为您完成的:
let groupedEnum (input: 'a seq) = seq {
use en = input.GetEnumerator()
let rec loop () = seq {
if en.MoveNext() then
yield en.Current
yield! loop () }
yield! loop () }编辑,为什么它在您的第一个示例中工作?F#列表类型返回的枚举数简单地忽略Dispose并继续工作,而如果对由string返回的枚举数调用Dispose,则不能再次使用该枚举数。(这可以说是F#列表类型的一些奇怪行为。)
https://stackoverflow.com/questions/13512519
复制相似问题