287 lines
9.9 KiB
Plaintext
287 lines
9.9 KiB
Plaintext
|
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<KeyValuePair<string, string>> datas)
|
||
|
{
|
||
|
object rootObj = Activator.CreateInstance(targetType);
|
||
|
Dictionary<string, object> objects = new Dictionary<string, object>()
|
||
|
{
|
||
|
{ "", rootObj },
|
||
|
};
|
||
|
List<string> currentStack = new List<string>();
|
||
|
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<T> Deserialize<T>(IListDataProvider datas)
|
||
|
{
|
||
|
foreach (var row in datas.Provide())
|
||
|
{
|
||
|
yield return (T)Deserialize(typeof(T), row);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Dictionary<string, T> Deserialize<T>(IMapDataProvider datas)
|
||
|
{
|
||
|
Dictionary<string, T> result = new Dictionary<string, T>();
|
||
|
foreach (var row in datas.Provide())
|
||
|
{
|
||
|
result.Add(row.Key, (T)Deserialize(typeof(T), row.Value));
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
private object EnsureParentObject(Dictionary<string, object> 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<string> currentStack, string[] newStack, Dictionary<string, object> 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<string, T> DeserializeMap<T>(IDataMatrix matrix)
|
||
|
{
|
||
|
Dictionary<string, T> result = new Dictionary<string, T>();
|
||
|
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<SubDataMatrix> 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<KeyValuePair<string, IDataMatrix>> 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<string, IDataMatrix>(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;
|
||
|
}
|
||
|
}
|
||
|
}
|