Skip to content

Commit fc57b26

Browse files
committed
Refactor ArrayReflectionConvertor: improve array deserialization logic and add ParseElementToMember method
1 parent 5876f67 commit fc57b26

1 file changed

Lines changed: 103 additions & 101 deletions

File tree

ReflectorNet/src/Convertor/Reflection/ArrayReflectionConvertor.Deserialize.cs

Lines changed: 103 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using System;
99
using System.Collections;
1010
using System.Collections.Generic;
11-
using System.Linq;
1211
using System.Text;
1312
using System.Text.Json;
1413
using com.IvanMurzak.ReflectorNet.Model;
@@ -56,22 +55,22 @@ public partial class ArrayReflectionConvertor : BaseReflectionConvertor<Array>
5655
: "IEnumerable");
5756
}
5857

59-
// Try to deserialize the value as a SerializedMemberList
60-
var serializedMemberList = data.valueJsonElement.Deserialize<SerializedMemberList>(reflector);
61-
// TODO: Need to support 'null' value. For the case when LLM needs to set exactly 'null' value for an array or list.
62-
if (serializedMemberList == null)
58+
// Check if the value is actually an array
59+
if (data.valueJsonElement == null || data.valueJsonElement.Value.ValueKind != JsonValueKind.Array)
6360
{
6461
if (logger?.IsEnabled(LogLevel.Warning) == true)
6562
{
66-
logger.LogWarning("{padding}{icon} Failed to deserialize 'value' json as '{typeName}'",
63+
logger.LogWarning("{padding}{icon} Failed to deserialize 'value' json as Array. Value is null or not an array.",
6764
padding,
68-
Consts.Emoji.Warn,
69-
nameof(SerializedMemberList));
65+
Consts.Emoji.Warn);
7066
}
71-
stringBuilder?.AppendLine($"{padding}[Warning] Failed to deserialize 'value' json as {nameof(SerializedMemberList)}.");
67+
stringBuilder?.AppendLine($"{padding}[Warning] Failed to deserialize 'value' json as Array.");
7268
return null;
7369
}
7470

71+
var jsonArray = data.valueJsonElement.Value;
72+
var length = jsonArray.GetArrayLength();
73+
7574
if (type.IsArray)
7675
{
7776
// Handle arrays
@@ -89,7 +88,7 @@ public partial class ArrayReflectionConvertor : BaseReflectionConvertor<Array>
8988
return null;
9089
}
9190

92-
var array = Array.CreateInstance(elementType, serializedMemberList.Count);
91+
var array = Array.CreateInstance(elementType, length);
9392
if (array == null)
9493
{
9594
if (logger?.IsEnabled(LogLevel.Warning) == true)
@@ -103,11 +102,13 @@ public partial class ArrayReflectionConvertor : BaseReflectionConvertor<Array>
103102
return null;
104103
}
105104

106-
for (int i = 0; i < serializedMemberList.Count; i++)
105+
int i = 0;
106+
foreach (var element in jsonArray.EnumerateArray())
107107
{
108-
var element = serializedMemberList[i];
108+
var member = ParseElementToMember(element);
109+
109110
var deserializedElement = reflector.Deserialize(
110-
data: element,
111+
data: member,
111112
fallbackType: elementType,
112113
depth: depth + 1,
113114
stringBuilder: stringBuilder,
@@ -117,6 +118,7 @@ public partial class ArrayReflectionConvertor : BaseReflectionConvertor<Array>
117118
{
118119
array.SetValue(deserializedElement, i);
119120
}
121+
i++;
120122
}
121123

122124
return array;
@@ -150,11 +152,12 @@ public partial class ArrayReflectionConvertor : BaseReflectionConvertor<Array>
150152
return null;
151153
}
152154

153-
foreach (var element in serializedMemberList)
155+
foreach (var element in jsonArray.EnumerateArray())
154156
{
155-
// logger?.LogTrace("{padding}Deserializing element: {ElementName}, typeName: {TypeName}", padding, element.name, element.typeName);
157+
var member = ParseElementToMember(element);
158+
156159
var deserializedElement = reflector.Deserialize(
157-
element,
160+
member,
158161
fallbackType: elementType,
159162
depth: depth + 1,
160163
stringBuilder: stringBuilder,
@@ -282,123 +285,89 @@ protected virtual bool TryDeserializeValueListInternal(
282285
try
283286
{
284287
name = name.ValueOrNull();
285-
var parsedList = jsonElement.Deserialize<SerializedMemberList>(reflector);
288+
289+
if (jsonElement == null)
290+
{
291+
result = null;
292+
return true;
293+
}
294+
295+
if (jsonElement.Value.ValueKind != JsonValueKind.Array)
296+
{
297+
result = null;
298+
return false;
299+
}
300+
301+
var jsonArray = jsonElement.Value;
302+
var count = jsonArray.GetArrayLength();
286303

287304
if (logger?.IsEnabled(LogLevel.Trace) == true)
288-
logger.LogTrace(parsedList == null
289-
? $"{padding}Deserializing '{name}' enumerable with 'null' value."
290-
: $"{padding}Deserializing '{name}' enumerable with {parsedList.Count} items.");
305+
logger.LogTrace($"{padding}Deserializing '{name}' enumerable with {count} items.");
291306

292307
if (stringBuilder != null)
293-
stringBuilder.AppendLine(parsedList == null
294-
? $"{padding}Deserializing '{name}' enumerable with 'null' value."
295-
: $"{padding}Deserializing '{name}' enumerable with {parsedList.Count} items.");
308+
stringBuilder.AppendLine($"{padding}Deserializing '{name}' enumerable with {count} items.");
296309

297310
var itemType = TypeUtils.GetEnumerableItemType(type);
298-
299-
var success = true;
300-
var enumerable = parsedList
301-
?.Select((element, i) =>
302-
{
303-
// TODO: need to use reflector.TryDeserialize
304-
var parsedValue = reflector.Deserialize(
305-
data: element,
306-
fallbackType: itemType,
307-
depth: depth + 1,
308-
stringBuilder: stringBuilder,
309-
logger: logger
310-
);
311-
// if (!success)
312-
// {
313-
// if (stringBuilder != null)
314-
// stringBuilder.AppendLine($"{paddingNext}[Error] Enumerable[{i}] deserialization failed: {errorMessage}");
315-
// return null;
316-
// }
317-
318-
if (logger?.IsEnabled(LogLevel.Trace) == true)
319-
logger.LogTrace($"{paddingNext}Enumerable[{i}] deserialized successfully: {parsedValue?.GetType().GetTypeShortName()}");
320-
321-
if (stringBuilder != null)
322-
stringBuilder.AppendLine($"{paddingNext}Enumerable[{i}] deserialized successfully.");
323-
324-
return parsedValue;
325-
});
326-
327-
if (!success)
311+
if (itemType == null)
328312
{
329313
result = null;
330-
331314
if (logger?.IsEnabled(LogLevel.Error) == true)
332-
logger.LogError($"{padding}Failed to deserialize '{name}': Some elements could not be deserialized.");
315+
logger.LogError($"{padding}Failed to determine element type for '{name}' of type '{type.GetTypeShortName()}'.");
333316

334317
if (stringBuilder != null)
335-
stringBuilder.AppendLine($"{padding}[Error] Failed to deserialize '{name}': Some elements could not be deserialized.");
336-
318+
stringBuilder.AppendLine($"{padding}[Error] Failed to determine element type for '{name}'.");
337319
return false;
338320
}
339321

340-
var elementType = TypeUtils.GetEnumerableItemType(type);
341-
if (elementType == null)
322+
var list = new List<object?>();
323+
int i = 0;
324+
foreach (var element in jsonArray.EnumerateArray())
342325
{
343-
result = null;
326+
var member = ParseElementToMember(element);
327+
var parsedValue = reflector.Deserialize(
328+
data: member,
329+
fallbackType: itemType,
330+
depth: depth + 1,
331+
stringBuilder: stringBuilder,
332+
logger: logger
333+
);
344334

345-
if (logger?.IsEnabled(LogLevel.Error) == true)
346-
logger.LogError($"{padding}Failed to determine element type for '{name}' of type '{type.GetTypeShortName()}'.");
335+
if (logger?.IsEnabled(LogLevel.Trace) == true)
336+
logger.LogTrace($"{paddingNext}Enumerable[{i}] deserialized successfully: {parsedValue?.GetType().GetTypeShortName()}");
347337

348338
if (stringBuilder != null)
349-
stringBuilder.AppendLine($"{padding}[Error] Failed to determine element type for '{name}'.");
339+
stringBuilder.AppendLine($"{paddingNext}Enumerable[{i}] deserialized successfully.");
350340

351-
return false;
341+
list.Add(parsedValue);
342+
i++;
352343
}
353344

354345
if (type.IsArray)
355346
{
356-
if (enumerable != null)
357-
{
358-
var typedArray = Array.CreateInstance(elementType, parsedList!.Count);
359-
var index = 0;
360-
foreach (var item in enumerable)
361-
{
362-
typedArray.SetValue(item, index++);
363-
}
364-
result = typedArray;
365-
366-
if (logger?.IsEnabled(LogLevel.Trace) == true)
367-
logger.LogTrace($"{padding}Deserialized '{name}' as an array with {typedArray.Length} items.");
368-
369-
if (stringBuilder != null)
370-
stringBuilder.AppendLine($"{padding}[Success] Deserialized '{name}' as an array with {typedArray.Length} items.");
371-
}
372-
else
347+
var typedArray = Array.CreateInstance(itemType, list.Count);
348+
for (int j = 0; j < list.Count; j++)
373349
{
374-
var tempResult = enumerable?.ToArray();
375-
result = tempResult;
376-
377-
if (logger?.IsEnabled(LogLevel.Trace) == true)
378-
logger.LogTrace(tempResult == null
379-
? $"{padding}Deserialized '{name}' as 'null' array."
380-
: $"{padding}Deserialized '{name}' as an array with {tempResult!.Length} items.");
381-
382-
if (stringBuilder != null)
383-
stringBuilder.AppendLine(tempResult == null
384-
? $"{padding}[Success] Deserialized '{name}' as 'null' array."
385-
: $"{padding}[Success] Deserialized '{name}' as an array with {tempResult!.Length} items.");
350+
typedArray.SetValue(list[j], j);
386351
}
352+
result = typedArray;
353+
354+
if (logger?.IsEnabled(LogLevel.Trace) == true)
355+
logger.LogTrace($"{padding}Deserialized '{name}' as an array with {typedArray.Length} items.");
356+
357+
if (stringBuilder != null)
358+
stringBuilder.AppendLine($"{padding}[Success] Deserialized '{name}' as an array with {typedArray.Length} items.");
387359
}
388360
else
389361
{
390-
var tempResult = enumerable?.ToList();
391-
result = tempResult;
362+
// Note: This creates a List<object?>. If the target is List<T>, this might need adjustment
363+
// but TryDeserializeValueListInternal returns IEnumerable, so it's usually iterated or cast later.
364+
result = list;
392365

393366
if (logger?.IsEnabled(LogLevel.Trace) == true)
394-
logger.LogTrace(tempResult == null
395-
? $"{padding}Deserialized '{name}' as 'null' list."
396-
: $"{padding}Deserialized '{name}' as a list with {tempResult.Count} items.");
367+
logger.LogTrace($"{padding}Deserialized '{name}' as a list with {list.Count} items.");
397368

398369
if (stringBuilder != null)
399-
stringBuilder.AppendLine(tempResult == null
400-
? $"{padding}[Success] Deserialized '{name}' as 'null' list."
401-
: $"{padding}[Success] Deserialized '{name}' as a list with {tempResult.Count} items.");
370+
stringBuilder.AppendLine($"{padding}[Success] Deserialized '{name}' as a list with {list.Count} items.");
402371
}
403372

404373
return true;
@@ -416,5 +385,38 @@ protected virtual bool TryDeserializeValueListInternal(
416385
return false;
417386
}
418387
}
388+
389+
protected virtual SerializedMember ParseElementToMember(JsonElement element)
390+
{
391+
SerializedMember? member = null;
392+
if (element.ValueKind == JsonValueKind.Object &&
393+
(
394+
element.TryGetProperty(nameof(SerializedMember.typeName), out _) ||
395+
element.TryGetProperty(nameof(SerializedMember.fields), out _) ||
396+
element.TryGetProperty(nameof(SerializedMember.props), out _))
397+
)
398+
{
399+
try
400+
{
401+
member = System.Text.Json.JsonSerializer.Deserialize<SerializedMember>(element.GetRawText());
402+
if (member != null && element.TryGetProperty("value", out var valueProp))
403+
{
404+
member.valueJsonElement = valueProp;
405+
}
406+
}
407+
catch
408+
{
409+
// Ignore deserialization errors here
410+
}
411+
}
412+
if (member == null)
413+
{
414+
member = new SerializedMember
415+
{
416+
valueJsonElement = element
417+
};
418+
}
419+
return member;
420+
}
419421
}
420422
}

0 commit comments

Comments
 (0)