1
+ using System . Linq ;
1
2
using System ;
2
3
using System . Collections ;
3
4
using System . Collections . Concurrent ;
4
5
using System . Collections . Generic ;
6
+ using System . Dynamic ;
5
7
using System . Reflection ;
6
8
7
9
namespace HotChocolate . Utilities ;
8
10
9
- internal class ObjectToDictionaryConverter
11
+ internal class ObjectToDictionaryConverter ( ITypeConverter converter )
10
12
{
11
- private readonly ITypeConverter _converter ;
12
- private readonly ConcurrentDictionary < Type , List < PropertyInfo > > _properties = new ( ) ;
13
-
14
- public ObjectToDictionaryConverter ( ITypeConverter converter )
15
- {
16
- _converter = converter
17
- ?? throw new ArgumentNullException ( nameof ( converter ) ) ;
18
- }
13
+ private readonly ITypeConverter _converter = converter ?? throw new ArgumentNullException ( nameof ( converter ) ) ;
14
+ private readonly ConcurrentDictionary < Type , PropertyInfo [ ] > _properties = new ( ) ;
19
15
20
16
public object Convert ( object obj )
21
17
{
22
- if ( obj is null )
18
+ if ( obj is null )
23
19
{
24
20
throw new ArgumentNullException ( nameof ( obj ) ) ;
25
21
}
26
22
27
23
object value = null ;
28
- Action < object > setValue = v => value = v ;
29
- VisitValue ( obj , setValue , new HashSet < object > ( ) ) ;
24
+ void SetValue ( object v ) => value = v ;
25
+ VisitValue ( obj , SetValue , new HashSet < object > ( ) ) ;
30
26
return value ;
31
27
}
32
28
33
29
private void VisitValue (
34
30
object obj ,
35
31
Action < object > setValue ,
36
- ISet < object > processed )
32
+ HashSet < object > processed )
37
33
{
38
34
if ( obj is null )
39
35
{
@@ -81,19 +77,56 @@ private void VisitValue(
81
77
private void VisitObject (
82
78
object obj ,
83
79
Action < object > setValue ,
84
- ISet < object > processed )
80
+ HashSet < object > processed )
85
81
{
86
82
if ( processed . Add ( obj ) )
87
83
{
88
- var dict = new Dictionary < string , object > ( ) ;
89
- setValue ( dict ) ;
84
+ var current = new Dictionary < string , object > ( ) ;
85
+ setValue ( current ) ;
90
86
91
- if ( obj is IReadOnlyDictionary < string , object > d )
87
+ if ( obj is Dictionary < string , object > dict1 )
88
+ {
89
+ foreach ( var item in dict1 )
90
+ {
91
+ void SetField ( object v ) => current [ item . Key ] = v ;
92
+ VisitValue ( item . Value , SetField , processed ) ;
93
+ }
94
+ }
95
+ else if ( obj is IDictionary < string , object > dict2 )
96
+ {
97
+ foreach ( var item in dict2 )
98
+ {
99
+ void SetField ( object v ) => current [ item . Key ] = v ;
100
+ VisitValue ( item . Value , SetField , processed ) ;
101
+ }
102
+ }
103
+ else if ( obj is IReadOnlyDictionary < string , object > dict3 )
92
104
{
93
- foreach ( var item in d )
105
+ foreach ( var item in dict3 )
94
106
{
95
- Action < object > setField = v => dict [ item . Key ] = v ;
96
- VisitValue ( item . Value , setField , processed ) ;
107
+ void SetField ( object v ) => current [ item . Key ] = v ;
108
+ VisitValue ( item . Value , SetField , processed ) ;
109
+ }
110
+ }
111
+ else if ( obj is IDictionary dict4 )
112
+ {
113
+ foreach ( var item in dict4 )
114
+ {
115
+ if ( item is DictionaryEntry entry )
116
+ {
117
+ void SetField ( object v ) => current [ entry . Key . ToString ( ) ! ] = v ;
118
+ VisitValue ( entry . Value , SetField , processed ) ;
119
+ }
120
+ else if ( item is KeyValuePair < string , object > pair )
121
+ {
122
+ void SetField ( object v ) => current [ pair . Key ] = v ;
123
+ VisitValue ( pair . Value , SetField , processed ) ;
124
+ }
125
+ else
126
+ {
127
+ throw new NotSupportedException (
128
+ $ "The dictionary entry type `{ item . GetType ( ) . FullName } ` is not supported.") ;
129
+ }
97
130
}
98
131
}
99
132
else
@@ -102,8 +135,8 @@ private void VisitObject(
102
135
{
103
136
var name = property . GetGraphQLName ( ) ;
104
137
var value = property . GetValue ( obj ) ;
105
- Action < object > setField = v => dict [ name ] = v ;
106
- VisitValue ( value , setField , processed ) ;
138
+ void SetField ( object v ) => current [ name ] = v ;
139
+ VisitValue ( value , SetField , processed ) ;
107
140
}
108
141
}
109
142
}
@@ -112,28 +145,29 @@ private void VisitObject(
112
145
private void VisitList (
113
146
ICollection list ,
114
147
Action < object > setValue ,
115
- ISet < object > processed )
148
+ HashSet < object > processed )
116
149
{
117
150
var valueList = new List < object > ( ) ;
118
151
setValue ( valueList ) ;
119
152
120
- Action < object > addItem = item => valueList . Add ( item ) ;
153
+ void AddItem ( object item ) => valueList . Add ( item ) ;
121
154
122
155
foreach ( var element in list )
123
156
{
124
- VisitValue ( element , addItem , processed ) ;
157
+ VisitValue ( element , AddItem , processed ) ;
125
158
}
126
159
}
127
160
128
- private IReadOnlyList < PropertyInfo > GetProperties ( object value )
161
+ private ReadOnlySpan < PropertyInfo > GetProperties ( object value )
129
162
{
130
163
var type = value . GetType ( ) ;
164
+
131
165
if ( ! _properties . TryGetValue ( type , out var properties ) )
132
166
{
133
- properties = new List < PropertyInfo > (
134
- ReflectionUtils . GetProperties ( type ) . Values ) ;
167
+ properties = ReflectionUtils . GetProperties ( type ) . Values . ToArray ( ) ;
135
168
_properties . TryAdd ( type , properties ) ;
136
169
}
170
+
137
171
return properties ;
138
172
}
139
173
}
0 commit comments