回答編集履歴

4

見直しキャンペーン中

2023/08/13 12:45

投稿

TN8001
TN8001

スコア9450

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

見直しキャンペーン中

2023/08/13 12:40

投稿

TN8001
TN8001

スコア9450

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

見直しキャンペーン中

2023/07/26 13:45

投稿

TN8001
TN8001

スコア9450

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
- ```C#
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
- ""LoginItem"": {
50
+ Console.WriteLine(loginItem.Count);
84
-
85
- ""ID"": ""TEST01""
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
- result = JsonConvert.DeserializeObject<Rootobject>(singleJson);
94
-
95
- loginItem = result.LoginList.LoginItem;
96
-
97
-
98
-
99
- Console.WriteLine(loginItem.Count);
100
-
101
- Console.WriteLine(string.Join(", ", loginItem.Select(x => x.ID)));
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

文修正

2021/02/04 09:28

投稿

TN8001
TN8001

スコア9450

test CHANGED
@@ -1,4 +1,6 @@
1
+ 型が変わってしまったらただただ扱いづらいだけです。
2
+
1
- 型が変わってしまったらただただ扱いづらいだけですから、実際にやりたいことはどちらを読んでも`List<Loginitem>`になることなんじゃないですか?
3
+ 実際にやりたいことはどちらを読んでも`List<Loginitem>`になることなんじゃないですか?
2
4
 
3
5
 
4
6