158 lines
4.0 KiB
C#
158 lines
4.0 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
|
|
namespace Gaia.FullSerializer.Internal
|
|
{
|
|
public class fsIEnumerableConverter : fsConverter
|
|
{
|
|
public override bool CanProcess(Type type)
|
|
{
|
|
if (!typeof(IEnumerable).IsAssignableFrom(type))
|
|
{
|
|
return false;
|
|
}
|
|
return GetAddMethod(type) != null;
|
|
}
|
|
|
|
public override object CreateInstance(fsData data, Type storageType)
|
|
{
|
|
return fsMetaType.Get(storageType).CreateInstance();
|
|
}
|
|
|
|
public override fsResult TrySerialize(object instance_, out fsData serialized, Type storageType)
|
|
{
|
|
IEnumerable enumerable = (IEnumerable)instance_;
|
|
fsResult success = fsResult.Success;
|
|
Type elementType = GetElementType(storageType);
|
|
serialized = fsData.CreateList(HintSize(enumerable));
|
|
List<fsData> asList = serialized.AsList;
|
|
foreach (object item in enumerable)
|
|
{
|
|
fsData data;
|
|
fsResult result = Serializer.TrySerialize(elementType, item, out data);
|
|
success.AddMessages(result);
|
|
if (!result.Failed)
|
|
{
|
|
asList.Add(data);
|
|
}
|
|
}
|
|
if (IsStack(enumerable.GetType()))
|
|
{
|
|
asList.Reverse();
|
|
}
|
|
return success;
|
|
}
|
|
|
|
private bool IsStack(Type type)
|
|
{
|
|
if (type.IsGenericType)
|
|
{
|
|
return type.GetGenericTypeDefinition() == typeof(Stack<>);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public override fsResult TryDeserialize(fsData data, ref object instance_, Type storageType)
|
|
{
|
|
IEnumerable enumerable = (IEnumerable)instance_;
|
|
fsResult success = fsResult.Success;
|
|
fsResult fsResult2 = (success += CheckType(data, fsDataType.Array));
|
|
if (fsResult2.Failed)
|
|
{
|
|
return success;
|
|
}
|
|
Type elementType = GetElementType(storageType);
|
|
MethodInfo addMethod = GetAddMethod(storageType);
|
|
MethodInfo flattenedMethod = storageType.GetFlattenedMethod("get_Item");
|
|
MethodInfo flattenedMethod2 = storageType.GetFlattenedMethod("set_Item");
|
|
if (flattenedMethod2 == null)
|
|
{
|
|
TryClear(storageType, enumerable);
|
|
}
|
|
int num = TryGetExistingSize(storageType, enumerable);
|
|
List<fsData> asList = data.AsList;
|
|
for (int i = 0; i < asList.Count; i++)
|
|
{
|
|
fsData data2 = asList[i];
|
|
object result = null;
|
|
if (flattenedMethod != null && i < num)
|
|
{
|
|
result = flattenedMethod.Invoke(enumerable, new object[1] { i });
|
|
}
|
|
fsResult result2 = Serializer.TryDeserialize(data2, elementType, ref result);
|
|
success.AddMessages(result2);
|
|
if (!result2.Failed)
|
|
{
|
|
if (flattenedMethod2 != null && i < num)
|
|
{
|
|
flattenedMethod2.Invoke(enumerable, new object[2] { i, result });
|
|
}
|
|
else
|
|
{
|
|
addMethod.Invoke(enumerable, new object[1] { result });
|
|
}
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
|
|
private static int HintSize(IEnumerable collection)
|
|
{
|
|
if (collection is ICollection)
|
|
{
|
|
return ((ICollection)collection).Count;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private static Type GetElementType(Type objectType)
|
|
{
|
|
if (objectType.HasElementType)
|
|
{
|
|
return objectType.GetElementType();
|
|
}
|
|
Type type = fsReflectionUtility.GetInterface(objectType, typeof(IEnumerable<>));
|
|
if (type != null)
|
|
{
|
|
return type.GetGenericArguments()[0];
|
|
}
|
|
return typeof(object);
|
|
}
|
|
|
|
private static void TryClear(Type type, object instance)
|
|
{
|
|
MethodInfo flattenedMethod = type.GetFlattenedMethod("Clear");
|
|
if (flattenedMethod != null)
|
|
{
|
|
flattenedMethod.Invoke(instance, null);
|
|
}
|
|
}
|
|
|
|
private static int TryGetExistingSize(Type type, object instance)
|
|
{
|
|
PropertyInfo flattenedProperty = type.GetFlattenedProperty("Count");
|
|
if (flattenedProperty != null)
|
|
{
|
|
return (int)flattenedProperty.GetGetMethod().Invoke(instance, null);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private static MethodInfo GetAddMethod(Type type)
|
|
{
|
|
Type type2 = fsReflectionUtility.GetInterface(type, typeof(ICollection<>));
|
|
if (type2 != null)
|
|
{
|
|
MethodInfo declaredMethod = type2.GetDeclaredMethod("Add");
|
|
if (declaredMethod != null)
|
|
{
|
|
return declaredMethod;
|
|
}
|
|
}
|
|
return type.GetFlattenedMethod("Add") ?? type.GetFlattenedMethod("Push") ?? type.GetFlattenedMethod("Enqueue");
|
|
}
|
|
}
|
|
}
|