From 49db3a28c84604c6a4812d56e5c40a87f1e84e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Mon, 15 Jan 2024 01:18:13 +0100 Subject: [PATCH] Fixed deserialization of generic types --- ScriptCore/Extensions/TypeExtension.cs | 93 +++++++++++++++++++ ScriptCore/ScriptCore.csproj | 4 + .../Serialization/DeserializationObject.cs | 21 +---- 3 files changed, 101 insertions(+), 17 deletions(-) diff --git a/ScriptCore/Extensions/TypeExtension.cs b/ScriptCore/Extensions/TypeExtension.cs index 7f538cd..b8026c4 100644 --- a/ScriptCore/Extensions/TypeExtension.cs +++ b/ScriptCore/Extensions/TypeExtension.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; using System.Reflection; using System.Text; @@ -65,4 +67,95 @@ public static class TypeExtension return attribute != null; } + + private static ReadOnlySpan ReadTypeName(ReadOnlySpan fullName) + { + for (int i = 0; i < fullName.Length; i++) + { + if (!char.IsLetterOrDigit(fullName[i]) && fullName[i] != '.' && fullName[i] != '+' && fullName[i] != '_') + { + return fullName.Slice(0, i); + } + } + + return fullName; + } + + public static Type? FindType(string fullName) + { + ReadOnlySpan rest = new ReadOnlySpan(); + + return FindType(fullName.AsSpan(), ref rest); + } + + private static Type? FindType(ReadOnlySpan fullName, ref ReadOnlySpan rest) + { + rest = fullName; + + ReadOnlySpan typeName = ReadTypeName(fullName); + rest = rest.Slice(typeName.Length); + + if (rest.IsEmpty || rest[0] != '`') + { + // Non generic type, easy! + return GetType(typeName); + } + + // Handle generic type + + int brackedIndex = fullName.IndexOf('['); + + typeName = fullName.Slice(0, brackedIndex); + rest = fullName.Slice(brackedIndex + 1).Trim(); + + Type? genericType = GetType(typeName); + + Console.WriteLine($"Generic Type: {genericType}"); + + List arguments = new List(); + + while (true) + { + Type? argument = FindType(rest, ref rest); + Console.WriteLine($"Argument: {argument}"); + + Debug.Assert(argument != null); + + arguments.Add(argument!); + + rest = rest.TrimStart(); + + if (rest.TrimStart()[0] == ',') + { + rest = rest.Slice(1); + } + else if (rest.TrimStart()[0] == ']') + { + rest = rest.Slice(1); + break; + } + else + { + break; + } + } + + return genericType?.MakeGenericType(arguments.ToArray()); + } + + private static Type? GetType(ReadOnlySpan fullName) + { + string name = fullName.TrimEnd(']').ToString(); + + // Non generic type, easy! + foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies().Reverse()) + { + Type? type = assembly.GetType(name); + + if (type != null) + return type; + } + + return null; + } } diff --git a/ScriptCore/ScriptCore.csproj b/ScriptCore/ScriptCore.csproj index 314a233..00f2a53 100644 --- a/ScriptCore/ScriptCore.csproj +++ b/ScriptCore/ScriptCore.csproj @@ -15,6 +15,10 @@ + + + + diff --git a/ScriptCore/Serialization/DeserializationObject.cs b/ScriptCore/Serialization/DeserializationObject.cs index 3faa1aa..e7cbd1b 100644 --- a/ScriptCore/Serialization/DeserializationObject.cs +++ b/ScriptCore/Serialization/DeserializationObject.cs @@ -87,26 +87,13 @@ public class DeserializationObject } } } - - public Type? FindType(string fullName) - { - foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies().Reverse()) - { - Type type = assembly.GetType(fullName); - - if (type != null) - return type; - } - - return null; - } - + public Type? GetTypeFromName(string fullName) { if (_fullNameToType.TryGetValue(fullName, out Type? storedType)) return storedType; - Type? type = FindType(fullName); + Type? type = TypeExtension.FindType(fullName); _fullNameToType.Add(fullName, type); @@ -270,7 +257,7 @@ public class DeserializationObject bool changed = false; - foreach (FieldInfo field in type.GetFields()) + foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) { if (!EntitySerializer.SerializeField(field)) continue; @@ -311,7 +298,7 @@ public class DeserializationObject } catch (Exception e) { - Log.Error(e); + Log.Exception(e); } return false;