nic*_*las 3 ienumerable f# idisposable
我试图从我简化的示例中吸取以下行为的教训:
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
Run Code Online (Sandbox Code Playgroud)
调查员"en"是否被独立处理?(我想这是关于ressources这个msdn doc旁边有什么可以说的/材料来阅读这个行为)
如果序列首先转换为列表,为什么它可以工作?
编辑:这只是一个玩具示例来说明行为,而不是被遵循.直接操纵枚举器的理由很少.
using一旦lambda函数返回,该函数就会处理枚举器.但是,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)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,异常处理变得非常困难,但我想这样做的一种方法是将主体包装并在异常发生时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 () }
Run Code Online (Sandbox Code Playgroud)
编辑为什么它在你的第一个例子中起作用?F#list类型返回的枚举器只是忽略Dispose并继续工作,而如果调用Disposea返回string的枚举器,则枚举器不能再次使用.(这可以说是F#列表类型有点奇怪的行为.)
| 归档时间: |
|
| 查看次数: |
951 次 |
| 最近记录: |