You need to enable JavaScript to run this app. F#如何使用Newtonsoft.Json反序列化私有可辨识联合?
优惠活动
大模型
产品
解决方案
定价
更多

F#如何使用Newtonsoft.Json反序列化私有可辨识联合?

问题根因

.NET 5+运行时搭配较高版本的Newtonsoft.Json时,识别F#私有可辨识联合(DU)的内部构造逻辑发生了变化,仅标注[<JsonObject(MemberSerialization = MemberSerialization.Fields)>]特性无法让Json.NET找到匹配的私有构造函数。你之前设置ConstructorHandling.AllowNonPublicDefaultConstructor无效的原因是F#的单例DU本身不存在无参构造函数,自然无法匹配该规则。

解决方案

无需修改DU为类类型,只需自定义适配私有DU的JsonConverter即可实现正常反序列化,完整可用代码如下:

open Newtonsoft.Json
open Newtonsoft.Json.Linq
open System.Reflection
open FSharp.Reflection

// 通用私有单例DU序列化转换器
type PrivateSingleCaseDUConverter<'T>() =
    inherit JsonConverter()
    override _.CanConvert(objectType: System.Type) = 
        objectType = typeof<'T> && FSharpType.IsUnion(objectType, BindingFlags.NonPublic ||| BindingFlags.Public)

    override _.WriteJson(writer: JsonWriter, value: obj, serializer: JsonSerializer) =
        serializer.Serialize(writer, value)

    override _.ReadJson(reader: JsonReader, objectType: System.Type, existingValue: obj, serializer: JsonSerializer) =
        let jObj = JObject.Load(reader)
        // 读取DU存储的载荷字段,默认序列化后字段名为Item
        let fieldValue = jObj["Item"].ToObject(typedefof<string>, serializer)
        // 反射获取私有DU的用例构造方法
        let unionCase = FSharpType.GetUnionCases(objectType, BindingFlags.NonPublic ||| BindingFlags.Public).[0]
        FSharpValue.MakeUnion(unionCase, [| fieldValue |])

[<JsonObject(MemberSerialization = MemberSerialization.Fields)>]
type Foo = private Bar of string

let f = Bar "f"
let s = JsonConvert.SerializeObject(f)
// 反序列化时传入自定义转换器即可
let f2 = JsonConvert.DeserializeObject<Foo>(s, PrivateSingleCaseDUConverter<Foo>())

printf "%A" f2

如果你的项目中存在大量同类型私有单例DU,也可以将转换器注册到全局JsonSerializerSettings中,无需每次调用反序列化方法时单独传入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 22:27:01