187 lines
6.1 KiB
C#
187 lines
6.1 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Runtime.Serialization;
|
|
using System.Text;
|
|
using GameDevWare.Serialization.MessagePack;
|
|
using GameDevWare.Serialization.Serializers;
|
|
|
|
// ReSharper disable once CheckNamespace
|
|
namespace GameDevWare.Serialization
|
|
{
|
|
public sealed class SerializationContext
|
|
{
|
|
private readonly Dictionary<Type, TypeSerializer> serializers;
|
|
private MessagePackExtensionTypeHandler extensionTypeHandler;
|
|
|
|
public Stack<object> Hierarchy { get; private set; }
|
|
public Stack<PathSegment> Path { get; private set; }
|
|
|
|
public IFormatProvider Format { get; set; }
|
|
public string[] DateTimeFormats { get; set; }
|
|
public Encoding Encoding { get; set; }
|
|
|
|
public Dictionary<Type, TypeSerializer> Serializers
|
|
{
|
|
get { return this.serializers; }
|
|
set
|
|
{
|
|
if (value == null) throw new ArgumentNullException("value");
|
|
|
|
foreach (var kv in value)
|
|
this.serializers[kv.Key] = kv.Value;
|
|
}
|
|
}
|
|
public MessagePackExtensionTypeHandler ExtensionTypeHandler
|
|
{
|
|
get { return this.extensionTypeHandler; }
|
|
set { if (value == null) throw new ArgumentNullException("value"); this.extensionTypeHandler = value; }
|
|
}
|
|
|
|
public SerializationOptions Options { get; set; }
|
|
|
|
public Func<Type, TypeSerializer> ObjectSerializerFactory { get; set; }
|
|
public Func<Type, TypeSerializer> EnumSerializerFactory { get; set; }
|
|
public Func<Type, TypeSerializer> DictionarySerializerFactory { get; set; }
|
|
public Func<Type, TypeSerializer> ArraySerializerFactory { get; set; }
|
|
public Func<Type, TypeSerializer> SerializerFactory { get; set; }
|
|
|
|
public SerializationContext()
|
|
{
|
|
this.Hierarchy = new Stack<object>();
|
|
this.Path = new Stack<PathSegment>();
|
|
|
|
this.Format = Json.DefaultFormat;
|
|
this.DateTimeFormats = Json.DefaultDateTimeFormats;
|
|
this.Encoding = Json.DefaultEncoding;
|
|
this.ExtensionTypeHandler = MsgPack.ExtensionTypeHandler;
|
|
|
|
this.serializers = Json.DefaultSerializers.ToDictionary(s => s.SerializedType);
|
|
}
|
|
|
|
public TypeSerializer GetSerializerForType(Type valueType)
|
|
{
|
|
if (valueType == null) throw new ArgumentNullException("valueType");
|
|
|
|
if (valueType.BaseType == typeof(MulticastDelegate) || valueType.BaseType == typeof(Delegate))
|
|
throw new InvalidOperationException(string.Format("Unable to serialize delegate type '{0}'.", valueType));
|
|
|
|
var serializer = default(TypeSerializer);
|
|
if (this.serializers.TryGetValue(valueType, out serializer))
|
|
return serializer;
|
|
|
|
var typeSerializerAttribute = valueType.GetCustomAttributes(typeof(TypeSerializerAttribute), inherit: false).FirstOrDefault() as TypeSerializerAttribute;
|
|
if (typeSerializerAttribute != null)
|
|
serializer = this.CreateCustomSerializer(valueType, typeSerializerAttribute);
|
|
else if (valueType.IsEnum)
|
|
serializer = this.CreateEnumSerializer(valueType);
|
|
else if (typeof(IDictionary).IsAssignableFrom(valueType) || valueType.IsInstantiationOf(typeof(IDictionary<,>)))
|
|
serializer = this.CreateDictionarySerializer(valueType);
|
|
else if (valueType.IsArray || typeof(IEnumerable).IsAssignableFrom(valueType))
|
|
serializer = this.CreateArraySerializer(valueType);
|
|
else
|
|
serializer = (this.SerializerFactory != null ? this.SerializerFactory(valueType) : null) ?? this.CreateObjectSerializer(valueType);
|
|
|
|
this.serializers.Add(valueType, serializer);
|
|
return serializer;
|
|
}
|
|
|
|
private TypeSerializer CreateDictionarySerializer(Type valueType)
|
|
{
|
|
if (this.DictionarySerializerFactory != null)
|
|
return this.DictionarySerializerFactory(valueType);
|
|
else
|
|
return new DictionarySerializer(valueType);
|
|
}
|
|
private TypeSerializer CreateEnumSerializer(Type valueType)
|
|
{
|
|
if (this.EnumSerializerFactory != null)
|
|
return this.EnumSerializerFactory(valueType);
|
|
else
|
|
return new EnumSerializer(valueType);
|
|
}
|
|
private TypeSerializer CreateArraySerializer(Type valueType)
|
|
{
|
|
if (this.ArraySerializerFactory != null)
|
|
return this.ArraySerializerFactory(valueType);
|
|
else
|
|
return new ArraySerializer(valueType);
|
|
}
|
|
private TypeSerializer CreateObjectSerializer(Type valueType)
|
|
{
|
|
if (this.ObjectSerializerFactory != null)
|
|
return this.ObjectSerializerFactory(valueType);
|
|
else
|
|
return new ObjectSerializer(this, valueType);
|
|
}
|
|
private TypeSerializer CreateCustomSerializer(Type valueType, TypeSerializerAttribute typeSerializerAttribute)
|
|
{
|
|
var serializerType = typeSerializerAttribute.SerializerType;
|
|
|
|
var typeCtr = serializerType.GetConstructor(new[] { typeof(Type) });
|
|
if (typeCtr != null)
|
|
return (TypeSerializer)typeCtr.Invoke(new object[] { valueType });
|
|
|
|
var ctxTypeCtr = serializerType.GetConstructor(new[] { typeof(SerializationContext), typeof(Type) });
|
|
if (ctxTypeCtr != null)
|
|
return (TypeSerializer)ctxTypeCtr.Invoke(new object[] { this, valueType });
|
|
|
|
var ctxCtr = serializerType.GetConstructor(new[] { typeof(SerializationContext) });
|
|
if (ctxCtr != null)
|
|
return (TypeSerializer)ctxCtr.Invoke(new object[] { this });
|
|
|
|
return (TypeSerializer)Activator.CreateInstance(serializerType);
|
|
}
|
|
|
|
public Type GetType(string name, bool throwOnError, bool ignoreCase)
|
|
{
|
|
return Type.GetType(name, throwOnError, ignoreCase);
|
|
}
|
|
public Type GetType(string name, bool throwOnError)
|
|
{
|
|
return Type.GetType(name, throwOnError);
|
|
}
|
|
public Type GetType(string name)
|
|
{
|
|
return Type.GetType(name);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reset serialization context for future re-use. Clears <see cref="Hierarchy"/> and <see cref="Path"/> collections.
|
|
/// </summary>
|
|
public void Reset()
|
|
{
|
|
this.Hierarchy.Clear();
|
|
this.Path.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get object hierarchy (arrays/objects) path to current reader position.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string GetPath()
|
|
{
|
|
var path = new StringBuilder();
|
|
foreach (var segment in this.Path.Reverse())
|
|
{
|
|
var segmentString = segment.ToString();
|
|
if (string.IsNullOrEmpty(segmentString))
|
|
{
|
|
continue;
|
|
}
|
|
path.Append(segmentString);
|
|
path.Append(".");
|
|
}
|
|
|
|
if (path.Length > 0)
|
|
{
|
|
path.Length--;
|
|
}
|
|
|
|
return path.ToString();
|
|
}
|
|
}
|
|
}
|