【问题标题】:How do you use CsvHelper.CsvWriter with F# option types?如何将 CsvHelper.CsvWriter 与 F# 选项类型一起使用?
【发布时间】:2021-05-29 17:55:51
【问题描述】:

我正在尝试使用 .Net CsvHelper 库将 F# 记录集合保存到 csv 文件。问题是选项类型没有正确转换为字符串。

#r "nuget: CsvHelper"

open System.IO 
open System.Globalization
open CsvHelper

type Record = { X : string; Y : float option }

let writeString x =
    use writer = new StringWriter()
    use csv = new CsvWriter(writer, CultureInfo.InvariantCulture)
    csv.WriteRecords(x)
    writer.ToString()

[{ X = "hi"; Y = Some 1.00}
 { X = "bye"; Y = None }]
|> writeString

我希望这里的第二个数据行中的第二个字段有一个空白值(或 CsvProvider 可以理解的任何其他 nan 值)。相反,CsvHelper 将 None 值转换为 0

val it : string = "X,Value
hi,1
bye,0
"

我知道FSharp.Data.CsvProvider 可以让我将此简单记录转换为可以保存的CsvFile.Row。但是,当您有很多字段时,这是一个糟糕的解决方案,因为很难保持CsvFile.Row 中字段的顺序(假设有 50 个浮点字段)。我更喜欢记录字段自动转换的解决方案。

【问题讨论】:

    标签: f# csvhelper


    【解决方案1】:

    CsvHelper 中似乎没有对 F# 的内置支持,因此您可能必须编写自己的 type converter 来处理选项。这是我快速制作的一个:

    open System.IO 
    open System.Globalization
    open CsvHelper
    open CsvHelper.TypeConversion
    
    type OptionConverter<'T>() =
        inherit DefaultTypeConverter()
        override __.ConvertToString(value, row, memberMapData) =
            match value :?> Option<'T> with
                | None -> ""
                | Some x -> base.ConvertToString(x, row, memberMapData)
    
    type Record = { X : string; Y : float option }
    
    let writeString x =
        use writer = new StringWriter()
        use csv = new CsvWriter(writer, CultureInfo.InvariantCulture)
        csv.Context.TypeConverterCache.AddConverter<Option<float>>(OptionConverter<float>())
        csv.WriteRecords(x)
        writer.ToString()
    
    [<EntryPoint>] 
    let main _ =
        [{ X = "hi"; Y = Some 1.00}
         { X = "bye"; Y = None }]
            |> writeString
            |> printfn "%s"
        0
    

    输出是:

    X,Y
    hi,1
    bye,
    

    FWIW,有一些 CSV 库在 F# 中更易于使用,例如 FSharp.Data CSV provider

    【讨论】:

    • 看起来真不错!我认为在 OptionConverter 中,我们需要 None -&gt; "" 而不是 None-&gt;null,以便我们在再见后得到一个“,”。另外,你有没有机会知道如何使用automapper 这样我就不必为 X 输入 Mapper?
    • 我经常使用 CsvProvider,但它没有一种简单的类型安全的方法来将记录转换为 CsvFile.Row。 fun (x:Record) -&gt; CsvFile.Row(x.X,x.Y) 有 50 个浮点字段时很容易导致字段混淆。
    • 我已将答案更新为自动映射并输出None 的空字符串。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多