@@ -6,7 +6,16 @@ open FSharp.Reflection
6
6
open System.Reflection .Emit
7
7
open System.Text .Json
8
8
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>
10
19
11
20
type internal RefobjFieldSetter < 'Record , 'Field > = Action< 'Record, 'Field>
12
21
type internal StructFieldSetter < 'Record , 'Field > = delegate of byref < 'Record > * 'Field -> unit
@@ -24,7 +33,7 @@ type internal RecordField<'Record> =
24
33
Name: string
25
34
Type: Type
26
35
Ignore: bool
27
- Serialize: Serializer
36
+ Serialize: Serializer < 'Record >
28
37
Deserialize: Deserializer < 'Record >
29
38
}
30
39
@@ -74,27 +83,39 @@ module internal RecordReflection =
74
83
setter.Invoke( record, value))
75
84
|> DRefobj
76
85
77
- let private serializer < 'Field > ( f : FieldInfo ) =
86
+ let private serializer < 'Record , ' Field> ( f : FieldInfo ) =
78
87
let getter =
79
88
let dynMethod =
80
89
new DynamicMethod(
81
90
f.Name,
82
91
f.FieldType,
83
- [| typeof< obj> |],
92
+ [|
93
+ ( if f.DeclaringType.IsValueType
94
+ then typeof< 'Record>. MakeByRefType()
95
+ else typeof< 'Record>)
96
+ |],
84
97
typedefof< RecordField<_>>. Module,
85
98
skipVisibility = true
86
99
)
87
100
let gen = dynMethod.GetILGenerator()
88
101
gen.Emit( OpCodes.Ldarg_ 0)
89
- if f.DeclaringType.IsValueType then
90
- gen.Emit( OpCodes.Unbox, f.DeclaringType)
91
102
gen.Emit( OpCodes.Ldfld, f)
92
103
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
98
119
99
120
let private thisModule = typedefof< RecordField<_>>. Assembly.GetType( " System.Text.Json.Serialization.RecordReflection" )
100
121
@@ -106,9 +127,9 @@ module internal RecordReflection =
106
127
||> Array.map2 ( fun f p ->
107
128
let serializer =
108
129
thisModule.GetMethod( " serializer" , BindingFlags.Static ||| BindingFlags.NonPublic)
109
- .MakeGenericMethod( p.PropertyType)
130
+ .MakeGenericMethod( recordTy , p.PropertyType)
110
131
.Invoke( null , [| f|])
111
- :?> Serializer
132
+ :?> Serializer< 'Record >
112
133
let deserializer =
113
134
thisModule.GetMethod( " deserializer" , BindingFlags.Static ||| BindingFlags.NonPublic)
114
135
.MakeGenericMethod( recordTy, p.PropertyType)
0 commit comments