我写了这个小小的网络监听模拟:
Agent.Start(fun (_ : MailboxProcessor<unit>) ->
let listener = new HttpListener()
listener.Prefixes.Add(addr)
listener.Start()
let rec respondOut() = async {
let! context = Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
use s = context.Response.OutputStream
let wr = new StreamWriter(s)
use disp = { new IDisposable with
member x.Dispose() =
printfn "Disposing..."
wr.Dispose() }
wr.Write("Test")
return! respondOut()
}
respondOut()
)
我不明白为什么每次循环都没有调用Dispose?
作为一个附带问题,我正在做这一切,因为我想测试在Web服务中响应文本的正确行为。我不确定我是否应该这样做:
use s = Context.Response.OutputStream
use sw = new StreamWriter(s)
sw.Write("test")
或
Context.Response.Write("Test")
Context.Response.End()
或诸如此类的。
谢谢!
答案 0 :(得分:5)
如有疑问,请使用反射器:)。 use关键字创建“使用”的范围,直到块的结尾。在异步工作流程中使用时,如果您对async关键字进行除糖,则会得到类似的内容:
Async.Bind(Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
(fun context ->
use s = context.Response.OutputStream
let wr = new StreamWriter(s)
use disp = { new IDisposable with
member x.Dispose() =
printfn "Disposing..."
wr.Dispose() }
wr.Write("Test")
Async.ReturnFrom ( respondOut() )
)
现在调用Async.ReturnFrom最后将继续以递归方式调用该函数,如果用“C#using(){}”替换使用,其中}括号位于Async.ReturnFrom之后,那么dispose永远不会被调用< / p>
将使用部分包装在do块中可以解决问题:
let rec respondOut() = async {
let! context = Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
do
use s = context.Response.OutputStream
let wr = new StreamWriter(s)
use disp = { new IDisposable with
member x.Dispose() =
printfn "Disposing..."
wr.Dispose() }
wr.Write("Test")
return! respondOut()
}
答案 1 :(得分:2)
use
延伸到块的末尾,所以我希望在递归计算返回之后将Dispose
称为(在这种情况下,从不它无条件地循环)。如果您想先处理资源,则需要以某种方式界定use
绑定的范围。也许这样的事情会起作用(我没试过):
let rec respondOut() = async {
let! context = Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
do! async {
use s = context.Response.OutputStream
let wr = new StreamWriter(s)
use disp = { new IDisposable with
member x.Dispose() =
printfn "Disposing..."
wr.Dispose() }
wr.Write("Test")
}
return! respondOut()
}
答案 2 :(得分:0)
我的猜测disp
已经在编译后的代码中进行了优化,因为它没有被使用。尝试在下一行添加printfn "%A" disp
。