@@ -6,7 +6,16 @@ open FSharp.Reflection
66open System.Reflection .Emit
77open System.Text .Json
88
9- type internal Serializer = Action< Utf8JsonWriter, obj, JsonSerializerOptions>
9+ type internal RefobjFieldGetter < 'Record , 'Field > = Func< 'Record, 'Field>
10+ type internal StructFieldGetter < 'Record , 'Field > = delegate of inref < 'Record > -> 'Field
11+
12+ type internal RefobjSerializer < 'Record > = Action< Utf8JsonWriter, 'Record, JsonSerializerOptions>
13+ type internal StructSerializer < 'Record > = delegate of Utf8JsonWriter * inref < 'Record > * JsonSerializerOptions -> unit
14+
15+ [<Struct>]
16+ type internal Serializer < 'Record > =
17+ | SStruct of s : StructSerializer<'Record>
18+ | SRefobj of n : RefobjSerializer<'Record>
1019
1120type internal RefobjFieldSetter < 'Record , 'Field > = Action< 'Record, 'Field>
1221type internal StructFieldSetter < 'Record , 'Field > = delegate of byref < 'Record > * 'Field -> unit
@@ -24,7 +33,7 @@ type internal RecordField<'Record> =
2433 Name: string
2534 Type: Type
2635 Ignore: bool
27- Serialize: Serializer
36+ Serialize: Serializer < 'Record >
2837 Deserialize: Deserializer < 'Record >
2938 }
3039
@@ -74,27 +83,39 @@ module internal RecordReflection =
7483 setter.Invoke( record, value))
7584 |> DRefobj
7685
77- let private serializer < 'Field > ( f : FieldInfo ) =
86+ let private serializer < 'Record , ' Field> ( f : FieldInfo ) =
7887 let getter =
7988 let dynMethod =
8089 new DynamicMethod(
8190 f.Name,
8291 f.FieldType,
83- [| typeof< obj> |],
92+ [|
93+ ( if f.DeclaringType.IsValueType
94+ then typeof< 'Record>. MakeByRefType()
95+ else typeof< 'Record>)
96+ |],
8497 typedefof< RecordField<_>>. Module,
8598 skipVisibility = true
8699 )
87100 let gen = dynMethod.GetILGenerator()
88101 gen.Emit( OpCodes.Ldarg_ 0)
89- if f.DeclaringType.IsValueType then
90- gen.Emit( OpCodes.Unbox, f.DeclaringType)
91102 gen.Emit( OpCodes.Ldfld, f)
92103 gen.Emit( OpCodes.Ret)
93- dynMethod.CreateDelegate( typeof< Func< obj, 'Field>>) :?> Func< obj, 'Field>
94- Serializer( fun writer record options ->
95- let v = getter.Invoke( record)
96- JsonSerializer.Serialize< 'Field>( writer, v, options)
97- )
104+ dynMethod
105+ if f.DeclaringType.IsValueType then
106+ let getter = getter.CreateDelegate( typeof< StructFieldGetter< 'Record, 'Field>>) :?> StructFieldGetter< 'Record, 'Field>
107+ StructSerializer< 'Record>( fun writer record options ->
108+ let v = getter.Invoke(& record)
109+ JsonSerializer.Serialize< 'Field>( writer, v, options)
110+ )
111+ |> SStruct
112+ else
113+ let getter = getter.CreateDelegate( typeof< RefobjFieldGetter< 'Record, 'Field>>) :?> RefobjFieldGetter< 'Record, 'Field>
114+ RefobjSerializer< 'Record>( fun writer record options ->
115+ let v = getter.Invoke( record)
116+ JsonSerializer.Serialize< 'Field>( writer, v, options)
117+ )
118+ |> SRefobj
98119
99120 let private thisModule = typedefof< RecordField<_>>. Assembly.GetType( " System.Text.Json.Serialization.RecordReflection" )
100121
@@ -106,9 +127,9 @@ module internal RecordReflection =
106127 ||> Array.map2 ( fun f p ->
107128 let serializer =
108129 thisModule.GetMethod( " serializer" , BindingFlags.Static ||| BindingFlags.NonPublic)
109- .MakeGenericMethod( p.PropertyType)
130+ .MakeGenericMethod( recordTy , p.PropertyType)
110131 .Invoke( null , [| f|])
111- :?> Serializer
132+ :?> Serializer< 'Record >
112133 let deserializer =
113134 thisModule.GetMethod( " deserializer" , BindingFlags.Static ||| BindingFlags.NonPublic)
114135 .MakeGenericMethod( recordTy, p.PropertyType)
0 commit comments