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

标签 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

这发生在异步 block 中。

这是为什么?

最佳答案

问题较少与use 部分有关,而更多与fixed 部分有关。 fixed 关键字确保值保留在堆栈中。将其与异步结合的问题是计算表达式中使用的局部变量并不总是保留在堆栈上。如果您在使用它们之间使用了 let!,则它们需要存储为对象的字段,因此 fixed 无法在此类上下文中工作。

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

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
    }

关于f# - 为什么我不能在 F# 的异步 block 中使用 'use',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71790058/

相关文章:

generics - F#:函数参数默认为类中的 obj

vb.net - 在 VB.NET 中定义 F# 函数

xml - 如何使用 FSharp 创建 XML 属性(而不是元素)?

f# - XSD.EXE 从 XSD 生成 F# 类

visual-studio-2010 - Visual Studio 中配置的编辑器语言在哪里?

wpf - 为什么程序退出时不触发 OnSessionEnding 事件?

f# - 既然函数是 F# 中的一等值,为什么不能使用 lambda 作为值?

f# - string.IsNullOrEmpty() 的 F# 等价物是什么?

map - 方法链 vs |> 管道操作符

javascript - 管理 Sitelet 中的资源