据我所知,use
关键字一旦超出范围就会处理绑定的IDisposable
,所以考虑这个递归函数:
let rec AsyncAcceptMessages(client : WebSocket) =
async {
let! message = client.AsyncReadMessage
use reader = new StreamReader(message)
let s = reader.ReadToEnd()
printf "%s" <| s
do! AsyncAcceptMessages client
}
让我们假装编译器没有找到使用尾递归的方法,在每次递归后会StreamReader
处理吗?
更新
Tomas的回应让我想到了一种方法来解决它,当你真正期待某些东西回来的时候,但如果你什么都没想到呢?就像在这个例子中StreamWriter
:
let rec AsyncAcceptMessages(client : WebSocket) =
async {
let! message = client.AsyncReadMessage
if(not(isNull message)) then
let s =
use reader = new StreamReader(message)
reader.ReadToEnd()
use writer = new StreamWriter(client.CreateMessageWriter(WebSocketMessageType.Text), Encoding.UTF8)
writer.Write s
printf "%s" <| s
do! AsyncAcceptMessages client
}
答案 0 :(得分:5)
正如您所说,StreamReader
只会在执行从递归调用返回后(即从不)处理。
还有另一个问题,即do!
不被视为尾递归调用,因此如果要创建无限尾递归循环,则需要使用return!
(否则)你的代码会泄漏内存。)
在这种情况下,您可以轻松地使用它进行修复,因为您没有使用StreamReader
进行任何异步操作,因此您只需创建一个普通的本地范围:
let rec AsyncAcceptMessages(client : WebSocket) =
async {
let! message = client.AsyncReadMessage
let s =
use reader = new StreamReader(message)
reader.ReadToEnd()
printf "%s" <| s
return! AsyncAcceptMessages client
}
如果你想打电话,例如AsyncReadToEnd
,然后您可以执行以下操作:
let rec AsyncAcceptMessages(client : WebSocket) =
async {
let! message = client.AsyncReadMessage
let! s =
async { use reader = new StreamReader(message)
return! reader.ReadToEnd() }
printf "%s" <| s
return! AsyncAcceptMessages client
}