using CommonSerializeDefine; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Text; using UnityEngine; namespace CommonSerializing { public class Deserializer : SerializerBase, IDeserializer { public object DeserializeData(Type targetType, string data) { ITypeSerializer serializer = EnsureSerializer(targetType); return serializer.Deserialize(data, targetType, this); } public object Deserialize(Type targetType, IEnumerable> datas) { object rootObj = Activator.CreateInstance(targetType); Dictionary objects = new Dictionary() { { "", rootObj }, }; List currentStack = new List(); foreach (var data in datas) { string dataPath = data.Key; string dataValue = data.Value; string[] newStack = SplitPath(dataPath); string fieldName = newStack[newStack.Length - 1]; object parentObj = EnsureParentObject(objects, newStack, newStack.Length - 1); FieldInfo field = EnsureField(parentObj.GetType(), fieldName); field.SetValue(parentObj, DeserializeData(field.FieldType, dataValue)); UpdateStack(currentStack, newStack, objects); } UpdateStack(currentStack, null, objects); return rootObj; } public IEnumerable Deserialize(IListDataProvider datas) { foreach (var row in datas.Provide()) { yield return (T)Deserialize(typeof(T), row); } } public Dictionary Deserialize(IMapDataProvider datas) { Dictionary result = new Dictionary(); foreach (var row in datas.Provide()) { result.Add(row.Key, (T)Deserialize(typeof(T), row.Value)); } return result; } private object EnsureParentObject(Dictionary objects, string[] objectPath, int objectPathCount) { string objectID = JoinString(".", objectPath, objectPathCount); object parentObj; if (objects.TryGetValue(objectID, out parentObj)) { return parentObj; } string fieldName = objectPath[objectPathCount - 1]; object grantParentObj = EnsureParentObject(objects, objectPath, objectPathCount - 1); FieldInfo field = EnsureField(grantParentObj.GetType(), fieldName); parentObj = field.GetValue(grantParentObj); if (parentObj == null) { parentObj = Activator.CreateInstance(field.FieldType); } if (!field.FieldType.IsValueType) { field.SetValue(grantParentObj, parentObj); } objects.Add(objectID, parentObj); return parentObj; } private void UpdateStack(List currentStack, string[] newStack, Dictionary objects) { int lastCommonIndex = -1; int newStackLength = newStack?.Length ?? 0; int min = currentStack.Count < newStackLength ? currentStack.Count : newStackLength; for (int i = 0; i < min; i++) { if (currentStack[i] != newStack[i]) { break; } else { lastCommonIndex = i; } } // Return to last common for (int i = currentStack.Count - 1; i > lastCommonIndex; i--) { string parentObjectID = JoinString(".", currentStack, i); string objectID = JoinString(".", currentStack, i + 1); string fieldName = currentStack[i]; object obj; if (!objects.TryGetValue(objectID, out obj)) { continue; } object parentObj = objects[parentObjectID]; FieldInfo field = EnsureField(parentObj.GetType(), fieldName); if (field.FieldType.IsValueType) { field.SetValue(parentObj, obj); } objects.Remove(objectID); } currentStack.RemoveRange(lastCommonIndex + 1, currentStack.Count - lastCommonIndex - 1); if (newStack != null) { for (int i = lastCommonIndex + 1; i < newStackLength; i++) { currentStack.Add(newStack[i]); } } } public Dictionary DeserializeMap(IDataMatrix matrix) { Dictionary result = new Dictionary(); foreach (var item in SplitToMap(matrix)) { result.Add(item.Key, (T)DeserializeObject(typeof(T), item.Value)); } return result; } private object DeserializeObject(Type targetType, IDataMatrix matrix, object rootObj = null) { rootObj = rootObj ?? Activator.CreateInstance(targetType); foreach (var subMatrix in SplitByColName(matrix)) { string dataPath = subMatrix.GetColName(1); string fieldName = dataPath; FieldInfo field = EnsureField(targetType, fieldName); Type fieldType = field.FieldType; object fieldObj; if (subMatrix.GetIsFinalColLayer(1)) { fieldObj = DeserializeData(field.FieldType, subMatrix[1, 1]); } else if (IsOrSubclassOf(fieldType, typeof(Dictionary<,>))) { IDictionary fieldDict = Activator.CreateInstance(fieldType) as IDictionary; foreach (var subItem in SplitToMap(subMatrix)) { string key = subItem.Key; object keyObject = DeserializeData(fieldType.GenericTypeArguments[0], key); fieldDict.Add(keyObject, DeserializeObject(fieldType.GenericTypeArguments[1], subItem.Value)); } fieldObj = fieldDict; } else if (IsOrSubclassOf(fieldType, typeof(List<>))) { fieldObj = null; } else { SubDataMatrix objMatrix = subMatrix; objMatrix.OffsetLayer++; fieldObj = DeserializeObject(field.FieldType, objMatrix, field.GetValue(rootObj)); } field.SetValue(rootObj, fieldObj); } return rootObj; } private IEnumerable SplitByColName(IDataMatrix matrix) { int lastSameCol = 1; string lastSameColName = matrix.GetColName(1); for (int col = 2; col <= matrix.Columns + 1; col++) { if (col == matrix.Columns + 1 || matrix.GetColName(col) != lastSameColName) { var subMatrix = new SubDataMatrix() { FromDataMatrix = matrix, OffsetRow = 0, OffsetCol = lastSameCol - 1, SizeRows = null, SizeColumns = col - lastSameCol, OffsetLayer = 0, }; yield return subMatrix; if (col != matrix.Columns + 1) { lastSameCol = col; lastSameColName = matrix.GetColName(col); } } } } private IEnumerable> SplitToMap(IDataMatrix matrix) { int lastNotEmptyRow = 1; bool waitingForYield = true; for (int row = 2; row <= matrix.Rows + 1; row++) { if (row == matrix.Rows + 1 || !string.IsNullOrEmpty(matrix[row, 1]) || matrix.IsRowEmpty(row)) { if (waitingForYield) { var subMatrix = new SubDataMatrix() { FromDataMatrix = matrix, OffsetRow = lastNotEmptyRow - 1, OffsetCol = 1, SizeRows = row - lastNotEmptyRow, SizeColumns = matrix.Columns - 1, OffsetLayer = 1, }; waitingForYield = false; yield return new KeyValuePair(matrix[lastNotEmptyRow, 1], subMatrix); } if (row == matrix.Rows + 1) { break; } if (!string.IsNullOrEmpty(matrix[row, 1])) { waitingForYield = true; lastNotEmptyRow = row; } } } } private static bool IsOrSubclassOf(Type test, Type parent) { if (test == parent || test.IsSubclassOf(parent)) { return true; } if (test.IsGenericType) { Type gen = test.GetGenericTypeDefinition(); if (gen == parent || gen.IsSubclassOf(parent)) { return true; } } return false; } } }