F#:将seq <'A>转换为seq <'B>的最快方法

时间:2019-06-06 10:10:00

标签: casting f# marten

我将Marten用作事件存储,尤其是要获取事件流。

stream

IReadOnlyList<IEvent>IEventpublic interface IEvent { Guid Id { get; set; } int Version { get; set; } long Sequence { get; set; } object Data { get; } Guid StreamId { get; set; } string StreamKey { get; set; } DateTimeOffset Timestamp { get; set; } string TenantId { get; set; } void Apply<TAggregate>(TAggregate state, IAggregator<TAggregate> aggregator) where TAggregate : class, new(); } 定义为:

IEvent

如果AccountEvents属性的基础类型是Data(如果不是,则不会将每个AccountEvents转换为as,顺序)。

在C#中,我将仅使用关键字let seqCastOption<'T> sequence = sequence |> Seq.map(fun x -> match box x with | :? 'T as value -> Some value | _ -> None) let fetchStream<'T> (session: IDocumentSession) (id: Guid) = let stream = session.Events.FetchStream(id) stream |> Seq.map(fun x -> x.Data) |> seqCastOption<'T> |> Seq.filter (fun x -> x.IsSome) |> Seq.map(fun x -> x.Value) 来实现这一目标,但是在F#中,我不确定(就性能而言)最快的F#ish方式是什么。

我结束了以下代码:

.Data

但这似乎很“昂贵”,我想知道将Option<AccountEvents>转换为IsSome +的步骤是否可以同时过滤{{1}}的步骤。 / p>

2 个答案:

答案 0 :(得分:6)

rmunn答案中提到的public ObservableCollection<MyItem> MyList { get; } = new ObservableCollection<MyItem>(); 函数对于这种情况的了解非常有用,但是对于这种情况,我建议使用内置的.NET方法Seq.choose,该方法确实可以完成您想要并且可能已经非常优化:

Enumerable.OfType<'T>

答案 1 :(得分:3)

Seq.choose是您一直在寻找的功能。您为它提供了一个函数,该函数采用'A并返回'B option,并产生'B的值Some。对于您的使用情况,它看起来像这样:

let castOption<'T> x =
    match box x with
    | :? 'T as value -> Some value
    | _ -> None

let fetchStream<'T> (session: IDocumentSession) (id: Guid) =
    let stream = session.Events.FetchStream(id)
    stream
    |> Seq.map(fun x -> x.Data)
    |> Seq.choose castOption<'T>