JSON反序列化:输入日期时间?输出选项<DateTime>

JSON deserialization: input DateTime? to output Option<DateTime>

上下文:

一种类型有两种表示形式:一种在 C# 中,一种在 F# 中。 C# 类型的值被序列化为 json,然后反序列化为 F# 类型的值。

是否有直接的方法将 null json 属性转换为 Option<> F# 值?

我面临这样一种情况,其中 null C# DateTime? UpdatedDate 属性 被序列化为 json,然后预计将被反序列化为 FSharpOption<DateTime> UpdatedDate破坏代码的值(F# 类型,C# 代码,长话短说...)。

我的 json 看起来像这样:

{
  "Property1": "1",
  "UpdatedDate": null,
  "Property2": "2"
}

我在技术上可以将我的 json 反序列化为包含 DateTime? UpdatedDate 的 C# 类型,然后将结果值映射到包含 FSharpOption<DateTime> UpdatedDate 的 F# 类型,但肯定有更好的方法...


编辑:

要反序列化 json 我正在使用 Newtonsoft 的 JsonConvert.DeserializeObject 和 .NET 5 + C# 9。

Newtonsoft.Json.FSharp 包中的

OptionConverter 可以为您解决这个问题。您的代码将如下所示:

let records =
    JsonConvert.DeserializeObject<MyType[]>(
       json,
       [| OptionConverter() :> JsonConverter |])

好的,感谢@brianberns 分享的示例,我明白了。示例代码:

public class DummyJsonConverter : JsonConverter<FSharpOption<DateTime>>
{
    public override FSharpOption<DateTime> Read(
        ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options) =>
        FSharpOption<DateTime>.None;

    public override void Write(
        Utf8JsonWriter writer,
        FSharpOption<DateTime> dateTimeValue,
        JsonSerializerOptions options) =>
        writer.WriteStringValue("");
}

用法:

var serializerOptions = new JsonSerializerOptions();

serializerOptions.Converters.Add(new DummyJsonConverter());

var whoisResponses = JsonSerializer.Deserialize<SharedSupport.Models.Whois.WhoisResponseV2[]>(
    snsMessage.Message,
    serializerOptions);

唯一需要注意的是,我用 System.Text.Json 序列化程序 (JsonSerializer) 替换了 Newtonsoft 序列化程序。


编辑:

按照@ruben-bartelink 的建议,我使用了建议的 nuget (FsCodec.NewtonsoftJson) 而不是我自己的自定义转换器。现在代码简单多了,因为我不必担心编写自己的转换。此外,我不必切换到 System.Text.Json.

var jsonSerializerSettings = new JsonSerializerSettings();

jsonSerializerSettings.Converters.Add(new OptionConverter());

var whoisResponses = JsonConvert.DeserializeObject<SharedSupport.Models.Whois.WhoisResponseV2[]>(
    snsMessage.Message,
    jsonSerializerSettings);