You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在F#中为IAsyncEnumerable传递CancellationToken的实现方案

在F#中实现带CancellationToken的IAsyncEnumerable扩展方法

你可以通过编写F#扩展方法,直接包装原IAsyncEnumerable并传递CancellationToken,实现和你C#代码一致的效果。以下是两种实现方式:

方式一:借助F#异步序列(需依赖FSharp.Control.AsyncSeq包)

这种方式代码更简洁,利用F#的asyncSeq语法糖构建异步序列,再转换为标准IAsyncEnumerable:

open System
open System.Threading
open System.Threading.Tasks
open System.Collections.Generic
open System.Runtime.CompilerServices
open FSharp.Control

[<Extension>]
module AsyncEnumerableExtensions =
    [<Extension>]
    [<EnumeratorCancellation>]
    let WithCancellationToken (source: IAsyncEnumerable<'T>) (ct: CancellationToken) =
        asyncSeq {
            use enumerator = source.GetAsyncEnumerator(ct)
            let! hasNext = enumerator.MoveNextAsync() |> Async.AwaitTask
            while hasNext do
                yield enumerator.Current
                let! hasNext = enumerator.MoveNextAsync() |> Async.AwaitTask
        } |> AsyncSeq.toAsyncEnumerable

方式二:手动实现IAsyncEnumerable(无外部依赖)

如果不想依赖第三方包,可以直接手动实现IAsyncEnumerable接口:

open System
open System.Threading
open System.Threading.Tasks
open System.Collections.Generic
open System.Runtime.CompilerServices

[<Extension>]
module AsyncEnumerableExtensions =
    [<Extension>]
    [<EnumeratorCancellation>]
    let WithCancellationToken (source: IAsyncEnumerable<'T>) (ct: CancellationToken) =
        { new IAsyncEnumerable<'T> with
            member _.GetAsyncEnumerator(cancellationToken: CancellationToken) =
                // 优先使用方法传入的令牌,若未提供则使用枚举时的令牌
                let effectiveCt = if ct = CancellationToken.None then cancellationToken else ct
                let innerEnumerator = source.GetAsyncEnumerator(effectiveCt)
                { new IAsyncEnumerator<'T> with
                    member _.Current = innerEnumerator.Current
                    member _.MoveNextAsync() = innerEnumerator.MoveNextAsync()
                    member _.DisposeAsync() = innerEnumerator.DisposeAsync() } }

使用示例

假设你已有IAsyncEnumerable<'a>实例和CancellationTokenSource,可直接像调用扩展方法一样使用:

open System.Threading

let cts = new CancellationTokenSource()
let myAsyncEnumerable = getTheAsyncEnumerable() // 你的IAsyncEnumerable实例
let cancellableEnumerable = myAsyncEnumerable.WithCancellationToken(cts.Token)

关键说明

  • [<Extension>]特性标记模块和方法,让它能像C#扩展方法一样被调用;
  • [<EnumeratorCancellation>]特性标记CancellationToken参数,确保令牌能正确传递到底层的GetAsyncEnumerator实现;
  • 两种方式都返回标准的IAsyncEnumerable<'T>,解决了你之前用TaskAsyncEnumerableExtensions.WithCancellation得到ConfiguredCancellableAsyncEnumerable无法转换的问题。

内容的提问来源于stack exchange,提问作者OrdinaryOrange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 01:24:51