在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
相关产品推荐
相关产品推荐

