回答編集履歴
4
見直しキャンペーン中
test
CHANGED
@@ -161,44 +161,6 @@
|
|
161
161
|
{
|
162
162
|
public SingleOrArrayConverter() : this(true) { }
|
163
163
|
public SingleOrArrayConverter(bool canWrite) : base(canWrite) { }
|
164
|
-
}
|
165
|
-
|
166
|
-
public class SingleOrArrayConverterFactory : JsonConverterFactory
|
167
|
-
{
|
168
|
-
public bool CanWrite { get; }
|
169
|
-
|
170
|
-
public SingleOrArrayConverterFactory() : this(true) { }
|
171
|
-
public SingleOrArrayConverterFactory(bool canWrite) => CanWrite = canWrite;
|
172
|
-
|
173
|
-
public override bool CanConvert(Type typeToConvert)
|
174
|
-
{
|
175
|
-
var itemType = GetItemType(typeToConvert);
|
176
|
-
if (itemType == null) return false;
|
177
|
-
if (itemType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(itemType)) return false;
|
178
|
-
return typeToConvert.GetConstructor(Type.EmptyTypes) != null && !typeToConvert.IsValueType;
|
179
|
-
}
|
180
|
-
|
181
|
-
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
|
182
|
-
{
|
183
|
-
var itemType = GetItemType(typeToConvert);
|
184
|
-
var converterType = typeof(SingleOrArrayConverter<,>).MakeGenericType(typeToConvert, itemType);
|
185
|
-
return (JsonConverter)Activator.CreateInstance(converterType, new object[] { CanWrite });
|
186
|
-
}
|
187
|
-
|
188
|
-
static Type GetItemType(Type type)
|
189
|
-
{
|
190
|
-
if (type.IsPrimitive || type.IsArray || type == typeof(string)) return null;
|
191
|
-
while (type != null)
|
192
|
-
{
|
193
|
-
if (type.IsGenericType)
|
194
|
-
{
|
195
|
-
var genType = type.GetGenericTypeDefinition();
|
196
|
-
if (genType == typeof(List<>)) return type.GetGenericArguments()[0];
|
197
|
-
}
|
198
|
-
type = type.BaseType;
|
199
|
-
}
|
200
|
-
return null;
|
201
|
-
}
|
202
164
|
}
|
203
165
|
|
204
166
|
public class SingleOrArrayConverter<TCollection, TItem> : JsonConverter<TCollection> where TCollection : class, ICollection<TItem>, new()
|
3
見直しキャンペーン中
test
CHANGED
@@ -85,3 +85,159 @@
|
|
85
85
|
}
|
86
86
|
}
|
87
87
|
```
|
88
|
+
|
89
|
+
---
|
90
|
+
|
91
|
+
System.Text.Json版
|
92
|
+
|
93
|
+
[c# - How to handle both a single item and an array for the same property using System.Text.Json? - Stack Overflow](https://stackoverflow.com/questions/59430728/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-system)
|
94
|
+
```cs
|
95
|
+
using System;
|
96
|
+
using System.Collections;
|
97
|
+
using System.Collections.Generic;
|
98
|
+
using System.Linq;
|
99
|
+
using System.Text.Json;
|
100
|
+
using System.Text.Json.Serialization;
|
101
|
+
|
102
|
+
namespace Questions320367
|
103
|
+
{
|
104
|
+
class Program
|
105
|
+
{
|
106
|
+
static void Main()
|
107
|
+
{
|
108
|
+
var arrayJson = @"
|
109
|
+
{
|
110
|
+
""LoginList"": {
|
111
|
+
""LoginItem"": [
|
112
|
+
{
|
113
|
+
""ID"": ""TEST01""
|
114
|
+
},
|
115
|
+
{
|
116
|
+
""ID"": ""TEST02""
|
117
|
+
}
|
118
|
+
]
|
119
|
+
}
|
120
|
+
}";
|
121
|
+
var result = JsonSerializer.Deserialize<Rootobject>(arrayJson);
|
122
|
+
List<Loginitem> loginItem = result.LoginList.LoginItem;
|
123
|
+
|
124
|
+
Console.WriteLine(loginItem.Count);
|
125
|
+
Console.WriteLine(string.Join(", ", loginItem.Select(x => x.ID)));
|
126
|
+
|
127
|
+
|
128
|
+
var singleJson = @"
|
129
|
+
{
|
130
|
+
""LoginList"": {
|
131
|
+
""LoginItem"": {
|
132
|
+
""ID"": ""TEST01""
|
133
|
+
}
|
134
|
+
}
|
135
|
+
}";
|
136
|
+
result = JsonSerializer.Deserialize<Rootobject>(singleJson);
|
137
|
+
loginItem = result.LoginList.LoginItem;
|
138
|
+
|
139
|
+
Console.WriteLine(loginItem.Count);
|
140
|
+
Console.WriteLine(string.Join(", ", loginItem.Select(x => x.ID)));
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
public class Rootobject
|
145
|
+
{
|
146
|
+
public Loginlist LoginList { get; set; }
|
147
|
+
}
|
148
|
+
public class Loginlist
|
149
|
+
{
|
150
|
+
[JsonConverter(typeof(SingleOrArrayConverter<Loginitem>))]
|
151
|
+
public List<Loginitem> LoginItem { get; set; }
|
152
|
+
}
|
153
|
+
public class Loginitem
|
154
|
+
{
|
155
|
+
public string ID { get; set; }
|
156
|
+
}
|
157
|
+
|
158
|
+
|
159
|
+
// [c# - How to handle both a single item and an array for the same property using System.Text.Json? - Stack Overflow](https://stackoverflow.com/questions/59430728/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-system)
|
160
|
+
public class SingleOrArrayConverter<TItem> : SingleOrArrayConverter<List<TItem>, TItem>
|
161
|
+
{
|
162
|
+
public SingleOrArrayConverter() : this(true) { }
|
163
|
+
public SingleOrArrayConverter(bool canWrite) : base(canWrite) { }
|
164
|
+
}
|
165
|
+
|
166
|
+
public class SingleOrArrayConverterFactory : JsonConverterFactory
|
167
|
+
{
|
168
|
+
public bool CanWrite { get; }
|
169
|
+
|
170
|
+
public SingleOrArrayConverterFactory() : this(true) { }
|
171
|
+
public SingleOrArrayConverterFactory(bool canWrite) => CanWrite = canWrite;
|
172
|
+
|
173
|
+
public override bool CanConvert(Type typeToConvert)
|
174
|
+
{
|
175
|
+
var itemType = GetItemType(typeToConvert);
|
176
|
+
if (itemType == null) return false;
|
177
|
+
if (itemType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(itemType)) return false;
|
178
|
+
return typeToConvert.GetConstructor(Type.EmptyTypes) != null && !typeToConvert.IsValueType;
|
179
|
+
}
|
180
|
+
|
181
|
+
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
|
182
|
+
{
|
183
|
+
var itemType = GetItemType(typeToConvert);
|
184
|
+
var converterType = typeof(SingleOrArrayConverter<,>).MakeGenericType(typeToConvert, itemType);
|
185
|
+
return (JsonConverter)Activator.CreateInstance(converterType, new object[] { CanWrite });
|
186
|
+
}
|
187
|
+
|
188
|
+
static Type GetItemType(Type type)
|
189
|
+
{
|
190
|
+
if (type.IsPrimitive || type.IsArray || type == typeof(string)) return null;
|
191
|
+
while (type != null)
|
192
|
+
{
|
193
|
+
if (type.IsGenericType)
|
194
|
+
{
|
195
|
+
var genType = type.GetGenericTypeDefinition();
|
196
|
+
if (genType == typeof(List<>)) return type.GetGenericArguments()[0];
|
197
|
+
}
|
198
|
+
type = type.BaseType;
|
199
|
+
}
|
200
|
+
return null;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
public class SingleOrArrayConverter<TCollection, TItem> : JsonConverter<TCollection> where TCollection : class, ICollection<TItem>, new()
|
205
|
+
{
|
206
|
+
public bool CanWrite { get; }
|
207
|
+
|
208
|
+
public SingleOrArrayConverter() : this(true) { }
|
209
|
+
public SingleOrArrayConverter(bool canWrite) => CanWrite = canWrite;
|
210
|
+
|
211
|
+
public override TCollection Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
212
|
+
{
|
213
|
+
switch (reader.TokenType)
|
214
|
+
{
|
215
|
+
case JsonTokenType.Null: return null;
|
216
|
+
case JsonTokenType.StartArray:
|
217
|
+
var list = new TCollection();
|
218
|
+
while (reader.Read())
|
219
|
+
{
|
220
|
+
if (reader.TokenType == JsonTokenType.EndArray) break;
|
221
|
+
list.Add(JsonSerializer.Deserialize<TItem>(ref reader, options));
|
222
|
+
}
|
223
|
+
return list;
|
224
|
+
default:
|
225
|
+
return new TCollection { JsonSerializer.Deserialize<TItem>(ref reader, options) };
|
226
|
+
}
|
227
|
+
}
|
228
|
+
public override void Write(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options)
|
229
|
+
{
|
230
|
+
if (CanWrite && value.Count == 1)
|
231
|
+
{
|
232
|
+
JsonSerializer.Serialize(writer, value.First(), options);
|
233
|
+
}
|
234
|
+
else
|
235
|
+
{
|
236
|
+
writer.WriteStartArray();
|
237
|
+
foreach (var item in value) JsonSerializer.Serialize(writer, item, options);
|
238
|
+
writer.WriteEndArray();
|
239
|
+
}
|
240
|
+
}
|
241
|
+
}
|
242
|
+
}
|
243
|
+
```
|
2
見直しキャンペーン中
test
CHANGED
@@ -1,173 +1,87 @@
|
|
1
|
-
型が変わってしまったらただただ扱いづらいだけです。
|
1
|
+
型が変わってしまったら、ただただ扱いづらいだけです。
|
2
|
-
|
3
|
-
実際にやりたいことは、どちらを読んでも`List<Loginitem>`になることな
|
2
|
+
実際にやりたいことは、どちらを読んでも`List<Loginitem>`になることではないですか?
|
4
|
-
|
5
|
-
|
6
3
|
|
7
4
|
[sendgrid - How to handle both a single item and an array for the same property using JSON.net - Stack Overflow](https://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n/18997172#18997172)
|
8
5
|
|
9
|
-
|
10
|
-
|
11
|
-
```
|
6
|
+
```cs
|
12
|
-
|
13
7
|
using Newtonsoft.Json;
|
14
|
-
|
15
8
|
using Newtonsoft.Json.Linq;
|
16
|
-
|
17
9
|
using System;
|
18
|
-
|
19
10
|
using System.Linq;
|
20
|
-
|
21
11
|
using System.Collections.Generic;
|
22
12
|
|
23
|
-
|
24
|
-
|
25
13
|
namespace Questions320367
|
26
|
-
|
27
14
|
{
|
28
|
-
|
29
15
|
class Program
|
30
|
-
|
31
16
|
{
|
32
|
-
|
33
17
|
static void Main()
|
34
|
-
|
35
18
|
{
|
36
|
-
|
37
19
|
var arrayJson = @"
|
38
|
-
|
39
20
|
{
|
40
|
-
|
41
21
|
""LoginList"": {
|
42
|
-
|
43
22
|
""LoginItem"": [
|
44
|
-
|
45
23
|
{
|
46
|
-
|
47
24
|
""ID"": ""TEST01""
|
48
|
-
|
49
25
|
},
|
50
|
-
|
51
26
|
{
|
52
|
-
|
53
27
|
""ID"": ""TEST02""
|
54
|
-
|
55
28
|
}
|
56
|
-
|
57
29
|
]
|
58
|
-
|
59
30
|
}
|
60
|
-
|
61
31
|
}";
|
62
|
-
|
63
32
|
var result = JsonConvert.DeserializeObject<Rootobject>(arrayJson);
|
64
|
-
|
65
33
|
List<Loginitem> loginItem = result.LoginList.LoginItem;
|
66
34
|
|
67
|
-
|
68
|
-
|
69
35
|
Console.WriteLine(loginItem.Count);
|
70
|
-
|
71
36
|
Console.WriteLine(string.Join(", ", loginItem.Select(x => x.ID)));
|
72
37
|
|
73
38
|
|
39
|
+
var singleJson = @"
|
40
|
+
{
|
41
|
+
""LoginList"": {
|
42
|
+
""LoginItem"": {
|
43
|
+
""ID"": ""TEST01""
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}";
|
47
|
+
result = JsonConvert.DeserializeObject<Rootobject>(singleJson);
|
48
|
+
loginItem = result.LoginList.LoginItem;
|
74
49
|
|
75
|
-
|
76
|
-
|
77
|
-
var singleJson = @"
|
78
|
-
|
79
|
-
{
|
80
|
-
|
81
|
-
""LoginList"": {
|
82
|
-
|
83
|
-
|
50
|
+
Console.WriteLine(loginItem.Count);
|
84
|
-
|
85
|
-
""ID
|
51
|
+
Console.WriteLine(string.Join(", ", loginItem.Select(x => x.ID)));
|
86
|
-
|
52
|
+
}
|
87
53
|
}
|
88
54
|
|
55
|
+
public class Rootobject
|
56
|
+
{
|
57
|
+
public Loginlist LoginList { get; set; }
|
89
|
-
}
|
58
|
+
}
|
59
|
+
public class Loginlist
|
60
|
+
{
|
61
|
+
[JsonConverter(typeof(SingleOrArrayConverter<Loginitem>))]
|
62
|
+
public List<Loginitem> LoginItem { get; set; }
|
63
|
+
}
|
64
|
+
public class Loginitem
|
65
|
+
{
|
66
|
+
public string ID { get; set; }
|
67
|
+
}
|
90
68
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
69
|
+
// [sendgrid - How to handle both a single item and an array for the same property using JSON.net - Stack Overflow](https://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n/18997172#18997172)
|
70
|
+
internal class SingleOrArrayConverter<T> : JsonConverter
|
71
|
+
{
|
72
|
+
public override bool CanConvert(Type objectType) => objectType == typeof(List<T>);
|
73
|
+
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
74
|
+
{
|
75
|
+
var token = JToken.Load(reader);
|
76
|
+
if (token.Type == JTokenType.Array)
|
77
|
+
{
|
78
|
+
return token.ToObject<List<T>>();
|
79
|
+
}
|
80
|
+
return new List<T> { token.ToObject<T>() };
|
103
81
|
}
|
104
82
|
|
83
|
+
public override bool CanWrite => false;
|
84
|
+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
|
105
85
|
}
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
public class Rootobject
|
110
|
-
|
111
|
-
{
|
112
|
-
|
113
|
-
public Loginlist LoginList { get; set; }
|
114
|
-
|
115
|
-
}
|
116
|
-
|
117
|
-
public class Loginlist
|
118
|
-
|
119
|
-
{
|
120
|
-
|
121
|
-
[JsonConverter(typeof(SingleOrArrayConverter<Loginitem>))]
|
122
|
-
|
123
|
-
public List<Loginitem> LoginItem { get; set; }
|
124
|
-
|
125
|
-
}
|
126
|
-
|
127
|
-
public class Loginitem
|
128
|
-
|
129
|
-
{
|
130
|
-
|
131
|
-
public string ID { get; set; }
|
132
|
-
|
133
|
-
}
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
// [sendgrid - How to handle both a single item and an array for the same property using JSON.net - Stack Overflow](https://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n/18997172#18997172)
|
138
|
-
|
139
|
-
internal class SingleOrArrayConverter<T> : JsonConverter
|
140
|
-
|
141
|
-
{
|
142
|
-
|
143
|
-
public override bool CanConvert(Type objectType) => objectType == typeof(List<T>);
|
144
|
-
|
145
|
-
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
146
|
-
|
147
|
-
{
|
148
|
-
|
149
|
-
var token = JToken.Load(reader);
|
150
|
-
|
151
|
-
if (token.Type == JTokenType.Array)
|
152
|
-
|
153
|
-
{
|
154
|
-
|
155
|
-
return token.ToObject<List<T>>();
|
156
|
-
|
157
|
-
}
|
158
|
-
|
159
|
-
return new List<T> { token.ToObject<T>() };
|
160
|
-
|
161
|
-
}
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
public override bool CanWrite => false;
|
166
|
-
|
167
|
-
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
|
168
|
-
|
169
|
-
}
|
170
|
-
|
171
86
|
}
|
172
|
-
|
173
87
|
```
|
1
文修正
test
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
+
型が変わってしまったらただただ扱いづらいだけです。
|
2
|
+
|
1
|
-
|
3
|
+
実際にやりたいことは、どちらを読んでも`List<Loginitem>`になることなんじゃないですか?
|
2
4
|
|
3
5
|
|
4
6
|
|