为什么我不能在 F# 中的异步块中使用 'use'

Why can't I use 'use' in an async block, in F#

我有这个函数可以从缓存中读取数据:

let private tryLoadFromCacheAsync filename =
    async {
        let filespec = makePath filename
        match File.Exists filespec with
        | true  ->
            let! bytes = File.ReadAllBytesAsync(filespec) |> Async.AwaitTask
            use pBytes = fixed bytes
            let sourceSpan = Span<byte>(NativePtr.toVoidPtr pBytes, bytes.Length)
            return Some (MemoryMarshal.Cast<byte, ShortTradeData>(sourceSpan).ToArray())
        | false ->
            return None
    }

兴趣线在这里:

use pBytes = fixed bytes

编译失败:

The type 'nativeptr<'a>' is not compatible with the type 'IDisposable'

但该行将编译为:

let pBytes = fixed bytes

这是在 async 块中发生的。

这是为什么?

问题与 use 部分无关,而与 fixed 部分有关。 fixed 关键字确保值保存在堆栈中。将它与 async 结合使用的问题是计算表达式中使用的局部变量并不总是保存在堆栈中。如果在它们的使用之间有 let!,它们需要存储为对象的字段,因此 fixed 不能在这种情况下工作。

您可以通过将固定变量的范围限制为 non-async 代码块来解决此问题:

let private tryLoadFromCacheAsync filename =
    async {
        let filespec = makePath filename
        match File.Exists filespec with
        | true  ->
            let! bytes = File.ReadAllBytesAsync(filespec) |> Async.AwaitTask
            let res = 
                use pBytes = fixed bytes
                let sourceSpan = Span<byte>(NativePtr.toVoidPtr pBytes, bytes.Length) 
                MemoryMarshal.Cast<byte, ShortTradeData>(sourceSpan).ToArray()
            return Some res 
        | false ->
            return None
    }