我在我的记录上使用自引用成员,如下所示:
type Payload =
{ Id: Guid }
member x.DerivedProperty = $"Derived Property using id: {x.Id}"
NewtonSoft.Json
将序列化这个,但是在迁移到System.Text.Json
之后,它不再包含在序列化中。
是否可以配置System.Text.Json
以包含自引用成员?
编辑:这似乎是FSharp.System.Text.Json
的副作用:https://github.com/Tarmil/FSharp.SystemTextJson/issues/92
寻找解决方案。请注意,如果我没有用FSharp.System.Text.Json
序列化Payload
,那么它将按预期序列化。
正如您在问题中指出的那样,无法序列化记录成员属性是JsonFSharpConverter
从FSharp.SystemTextJson
的已知限制,请参阅序列化记录类型#92的成员属性:
输出不包含成员属性。删除选项中的转换器,它确实会被打印出来。
但是JsonFSharpConverter
实际上对记录类型做了什么?事实证明,这个转换器是一个为f#记录类型生产JsonRecordConverter<'T>
的工厂。从其源代码来看,JsonRecordConverter<'T>
带来的主要优点是它总是使用其参数化构造函数构造记录。这对于。net Core 3.1中的所有记录都是必需的,对于内部记录可能仍然需要。在。net 5和更高版本中。[1]此外,还可能需要正确序列化内部记录的任何字段——我还没有测试过。<一口>[2]一口>
因为似乎你不需要为你的Payload
类型应用转换器,你可以选择不使用JsonFSharpConverter
封装在一些装饰器工厂,其CanConvert(Type)
方法返回false的类型,你想使用默认序列化。
例如,您可以创建一个转换器工厂,当应用某些自定义属性时,它选择不使用FSharp.System.Text.Json
:
type JsonConverterFactoryDecorator (innerConverter : JsonConverterFactory) =
inherit JsonConverterFactory ()
member private this.innerConverter = match innerConverter with | null -> nullArg "innerConverter" | _ -> innerConverter // Guard against null if called from c# serialization code
override this.CanConvert(t) = innerConverter.CanConvert(t)
override this.CreateConverter(typeToConvert, options) = innerConverter.CreateConverter(typeToConvert, options)
type OptOutJsonConverterFactoryDecorator<'T when 'T :> System.Attribute> (innerConverter : JsonConverterFactory) =
inherit JsonConverterFactoryDecorator (innerConverter)
override this.CanConvert(t) = base.CanConvert(t) && not (t.IsDefined(typeof<'T>, false))
type JsonFSharpConverterOptOutAttribute () =
inherit System.Attribute()
type OptOutJsonFSharpConverter () =
inherit OptOutJsonConverterFactoryDecorator<JsonFSharpConverterOptOutAttribute>(JsonFSharpConverter())
然后按如下方式装饰Payload
:
[<JsonFSharpConverterOptOut>]
type Payload =
{ Id: Guid }
member x.DerivedProperty = "Derived Property using id: {x.Id}"
或者,如果您更愿意为所有记录选择不使用FSharp.System.Text.Json
,则定义OptOutJsonFSharpConverter
如下:
type OptOutJsonFSharpConverter () =
inherit JsonConverterFactoryDecorator(JsonFSharpConverter())
override this.CanConvert(t) = base.CanConvert(t) && not (Microsoft.FSharp.Reflection.FSharpType.IsRecord(t, BindingFlags.Public ||| BindingFlags.NonPublic))
(你可能需要尝试获得最合适的记录序列化,例如,你可能需要检查t.IsPublic
以重新启用JsonFSharpConverter
用于内部记录)
无论您选择哪个版本的OptOutJsonFSharpConverter
,都要按如下方式初始化您的选项:
let options = JsonSerializerOptions()
options.Converters.Add(OptOutJsonFSharpConverter ())
[1]参见f#内部可见性变化记录构造函数行为了解详细信息。
[2]参见内部类型的字段和方法不可能公开#2820