Skip to content

Instantly share code, notes, and snippets.

@rpgmaker
Created October 21, 2013 05:33
Show Gist options
  • Save rpgmaker/7079123 to your computer and use it in GitHub Desktop.
Save rpgmaker/7079123 to your computer and use it in GitHub Desktop.
JSON Serializer First Draft
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Phoenix.Json {
public abstract class PhoenixSerializer<T> {
public abstract string Serialize(T value);
}
public static class PhoenixJson {
const string QuotChar = "\"";
static string[] digits = new string[]{
"00010203040506070809",
"10111213141516171819",
"20212223242526272829",
"30313233343536373839",
"40414243444546474849",
"50515253545556575859",
"60616263646566676869",
"70717273747576777879",
"80818283848586878889",
"90919293949596979899"
};
unsafe static char* digit_pairs = (char*)Marshal.StringToHGlobalAuto(String.Join(String.Empty, digits)).ToPointer();
const int BUFFER_SIZE = 11;
const int BUFFER_SIZE_DIFF = BUFFER_SIZE - 2;
const TypeAttributes TypeAttribute =
TypeAttributes.Public | TypeAttributes.Serializable | TypeAttributes.Sealed;
const BindingFlags PropertyBinding = BindingFlags.Instance | BindingFlags.Public;
const BindingFlags MethodBinding = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
const MethodAttributes MethodAttribute =
MethodAttributes.Public
| MethodAttributes.Virtual
| MethodAttributes.Final
| MethodAttributes.HideBySig
| MethodAttributes.NewSlot
| MethodAttributes.SpecialName;
const MethodAttributes StaticMethodAttribute =
MethodAttributes.Public
| MethodAttributes.Static
| MethodAttributes.Final
| MethodAttributes.HideBySig
| MethodAttributes.NewSlot
| MethodAttributes.SpecialName;
static readonly Type _dateTimeType = typeof(DateTime),
_stringType = typeof(String),
_byteArrayType = typeof(byte[]),
_charType = typeof(char),
_guidType = typeof(Guid),
_boolType = typeof(bool),
_timeSpanType = typeof(TimeSpan),
_stringBuilderType = typeof(StringBuilder),
_listType = typeof(IList),
_dictType = typeof(IDictionary),
_genericDictType = typeof(Dictionary<,>),
_genericListType = typeof(List<>),
_objectType = typeof(Object),
_nullableType = typeof(Nullable<>),
_decimalType = typeof(decimal),
_genericKeyValuePairType = typeof(KeyValuePair<,>),
_serializerType = typeof(PhoenixSerializer<>),
_genericDictionaryEnumerator =
Type.GetType("System.Collections.Generic.Dictionary`2+Enumerator"),
_genericListEnumerator =
Type.GetType("System.Collections.Generic.List`1+Enumerator"),
_typeType = typeof(Type),
_voidType = typeof(void),
_intType = typeof(int),
_jsonType = typeof(PhoenixJson);
static readonly MethodInfo _stringBuilderToString =
_stringBuilderType.GetMethod("ToString", Type.EmptyTypes),
_stringBuilderAppend = _stringBuilderType.GetMethod("Append", new[] { _stringType }),
_stringBuilderAppendChar = _stringBuilderType.GetMethod("Append", new[] { _charType }),
_stringBuilderClear = _stringBuilderType.GetMethod("Clear"),
_stringOpEquality = _stringType.GetMethod("op_Equality", MethodBinding),
_generatorGetStringBuilder = _jsonType.GetMethod("GetStringBuilder", MethodBinding),
_generatorIntToStr = _jsonType.GetMethod("IntToStr", MethodBinding),
_generatorDateToString = _jsonType.GetMethod("DateToString", MethodBinding),
_generatorDateToISOFormat = _jsonType.GetMethod("DateToISOFormat", MethodBinding),
_objectToString = _objectType.GetMethod("ToString", Type.EmptyTypes),
_stringFormat = _stringType.GetMethod("Format", new[] { typeof(string), typeof(object) }),
_convertBase64 = typeof(Convert).GetMethod("ToBase64String", new[] { typeof(byte[]) }),
_iDisposableDispose = typeof(IDisposable).GetMethod("Dispose"),
_stringConcat = _stringType.GetMethod("Concat", new[] { _objectType, _objectType, _objectType, _objectType });
const int Delimeter = (int)',',
ArrayOpen = (int)'[', ArrayClose = (int)']', ObjectOpen = (int)'{', ObjectClose = (int)'}';
const string IsoFormat = "{0:yyyy-MM-ddTHH:mm:ss.fffZ}",
ClassStr = "Class", _dllStr = ".dll",
NullStr = "null",
IListStr = "IList`1",
IDictStr = "IDictionary`2",
WriteStr = "Write", ReadStr = "Read",
QuoteChar = "`",
ArrayStr = "Array", AnonymousBracketStr = "<>",
ArrayLiteral = "[]",
Colon = ":",
SerializeStr = "Serialize", DeserializeStr = "Deserialize";
static readonly ConcurrentDictionary<Type, Type> _types =
new ConcurrentDictionary<Type, Type>();
static readonly ConcurrentDictionary<string, MethodBuilder> _writeMethodBuilders =
new ConcurrentDictionary<string, MethodBuilder>();
static readonly ConcurrentDictionary<Type, bool> _primitiveTypes =
new ConcurrentDictionary<Type, bool>();
static readonly ConcurrentDictionary<int, StringBuilder> _stringBuilders =
new ConcurrentDictionary<int, StringBuilder>();
static readonly ConcurrentDictionary<int, StringBuilder> _dateStringBuilders =
new ConcurrentDictionary<int, StringBuilder>();
static readonly ConcurrentDictionary<Type, object> _serializers = new ConcurrentDictionary<Type, object>();
static readonly ConcurrentDictionary<Type, IEnumerable<PropertyInfo>> _typeProperties =
new ConcurrentDictionary<Type, IEnumerable<PropertyInfo>>();
static readonly ConcurrentDictionary<string, string> _fixes =
new ConcurrentDictionary<string, string>();
const int DefaultStringBuilderCapacity = 1024 * 2;
private readonly static object _lockObject = new object();
private static unsafe void memcpy(char* dmem, char* smem, int charCount) {
if ((((int)dmem) & 2) != 0) {
dmem[0] = smem[0];
dmem++;
smem++;
charCount--;
}
while (charCount >= 8) {
*((int*)dmem) = *((int*)smem);
*((int*)(dmem + 2)) = *((int*)(smem + 2));
*((int*)(dmem + 4)) = *((int*)(smem + 4));
*((int*)(dmem + 6)) = *((int*)(smem + 6));
dmem += 8;
smem += 8;
charCount -= 8;
}
if ((charCount & 4) != 0) {
*((int*)dmem) = *((int*)smem);
*((int*)(dmem + 2)) = *((int*)(smem + 2));
dmem += 4;
smem += 4;
}
if ((charCount & 2) != 0) {
*((int*)dmem) = *((int*)smem);
dmem += 2;
smem += 2;
}
if ((charCount & 1) != 0) {
dmem[0] = smem[0];
}
}
public unsafe static string IntToStr(int val) {
char* buf = stackalloc char[BUFFER_SIZE];
char* it = (char*)&buf[BUFFER_SIZE_DIFF];
if (val >= 0) {
int div = val / 100;
while (div != 0) {
memcpy(it, &digit_pairs[2 * (val - div * 100)], 2);
val = div;
it -= 2;
div = val / 100;
}
memcpy(it, &digit_pairs[2 * val], 2);
if (val < 10)
it++;
} else {
int div = val / 100;
while (div != 0) {
memcpy(it, &digit_pairs[-2 * (val - div * 100)], 2);
val = div;
it -= 2;
div = val / 100;
}
memcpy(it, &digit_pairs[-2 * val], 2);
if (val <= -10)
it--;
*it = '-';
}
return new string(it);
}
internal static string ReplaceEx(this string original, string pattern, string replacement,
StringComparison comparisonType = StringComparison.Ordinal, int stringBuilderInitialSize = -1) {
if (original == null) {
return null;
}
if (String.IsNullOrEmpty(pattern)) {
return original;
}
int posCurrent = 0;
int lenPattern = pattern.Length;
int idxNext = original.IndexOf(pattern, comparisonType);
StringBuilder result = new StringBuilder(stringBuilderInitialSize < 0 ? Math.Min(4096, original.Length) : stringBuilderInitialSize);
while (idxNext >= 0) {
result.Append(original, posCurrent, idxNext - posCurrent);
result.Append(replacement);
posCurrent = idxNext + lenPattern;
idxNext = original.IndexOf(pattern, posCurrent, comparisonType);
}
result.Append(original, posCurrent, original.Length - posCurrent);
return result.ToString();
}
public static bool IsPrimitiveType(this Type type) {
return _primitiveTypes.GetOrAdd(type, key =>
{
if (key.IsGenericType &&
key.GetGenericTypeDefinition() == _nullableType)
key = key.GetGenericArguments()[0];
return key == _stringType ||
key.IsPrimitive || key == _dateTimeType ||
key == _decimalType || key == _timeSpanType ||
key == _guidType ||
key.IsEnum || key == _byteArrayType;
});
}
internal static IEnumerable<PropertyInfo> GetTypeProperties(this Type type) {
return _typeProperties.GetOrAdd(type, key => key.GetProperties(PropertyBinding));
}
internal static bool IsListType(this Type type) {
return _listType.IsAssignableFrom(type) || type.Name == IListStr;
}
internal static bool IsDictionaryType(this Type type) {
return _dictType.IsAssignableFrom(type) || type.Name == IDictStr;
}
public static bool IsCollectionType(this Type type) {
return type.IsListType() || type.IsDictionaryType();
}
public static bool IsClassType(this Type type) {
return !type.IsCollectionType() && !type.IsPrimitiveType();
}
public static StringBuilder GetStringBuilder() {
return _stringBuilders.GetOrAdd(Thread.CurrentThread.ManagedThreadId, key => new StringBuilder(DefaultStringBuilderCapacity));
}
private static bool _useTickFormat = true;
public static bool UseISOFormat {
set {
_useTickFormat = !value;
}
}
public static string DateToISOFormat(DateTime date) {
return _dateStringBuilders.GetOrAdd(Thread.CurrentThread.ManagedThreadId, key => new StringBuilder(25))
.Clear().Append(IntToStr(date.Year)).Append('-').Append(IntToStr(date.Month))
.Append('-').Append(IntToStr(date.Day)).Append('T').Append(IntToStr(date.Hour)).Append(':').Append(IntToStr(date.Minute)).Append(':')
.Append(IntToStr(date.Second)).Append('.').Append(IntToStr(date.Millisecond)).Append('Z').ToString();
}
public static string DateToString(DateTime date) {
return String.Concat("\\/Date(", ((date.Ticks - 621355968000000000) / 0x2710L).ToString(), ")\\/");
}
internal static Type Generate(Type objType) {
var returnType = default(Type);
if (_types.TryGetValue(objType, out returnType))
return returnType;
var isPrimitive = objType.IsPrimitiveType();
var genericType = _serializerType.MakeGenericType(objType);
var typeName = objType.Name;
var asmName = String.Concat(typeName, ClassStr);
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName(asmName)
{
Version = new Version(1, 0, 0, 0)
},
AssemblyBuilderAccess.RunAndSave);
var module = assembly.DefineDynamicModule(String.Concat(typeName, _dllStr));
var type = module.DefineType(typeName, TypeAttribute, genericType);
var writeMethod = WriteSerializeMethodFor(type, objType, needQuote: !isPrimitive);
var serializeMethod = type.DefineMethod(SerializeStr, MethodAttribute,
_stringType, new[] { objType });
var il = serializeMethod.GetILGenerator();
var sbLocal = il.DeclareLocal(_stringBuilderType);
il.Emit(OpCodes.Call, _generatorGetStringBuilder);
il.Emit(OpCodes.Callvirt, _stringBuilderClear);
il.Emit(OpCodes.Stloc, sbLocal.LocalIndex);
//il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldloc, sbLocal.LocalIndex);
il.Emit(OpCodes.Call, writeMethod);
il.Emit(OpCodes.Ldloc, sbLocal.LocalIndex);
il.Emit(OpCodes.Callvirt, _stringBuilderToString);
il.Emit(OpCodes.Ret);
type.DefineMethodOverride(serializeMethod,
genericType.GetMethod(SerializeStr));
returnType = type.CreateType();
_types[objType] = returnType;
//assembly.Save(String.Concat(typeName, _dllStr));
return returnType;
}
public static string GetName(this Type type) {
var sb = new StringBuilder();
var arguments =
!type.IsGenericType ? Type.EmptyTypes :
type.GetGenericArguments();
if (!type.IsGenericType) {
sb.Append(type.Name);
} else {
sb.Append(type.Name);
foreach (var argument in arguments)
sb.Append(GetName(argument));
}
return sb.ToString();
}
public static string Fix(this string name) {
return _fixes.GetOrAdd(name, key =>
{
var index = key.IndexOf(QuoteChar, StringComparison.OrdinalIgnoreCase);
var quoteText = index > -1 ? key.Substring(index, 2) : QuoteChar;
var value = key.Replace(quoteText, string.Empty).Replace(ArrayLiteral, ArrayStr).Replace(AnonymousBracketStr, string.Empty);
if (value.Contains(QuoteChar))
value = Fix(value);
return value;
});
}
internal static MethodInfo WriteSerializeMethodFor(TypeBuilder typeBuilder, Type type, bool needQuote = true) {
MethodBuilder method;
var key = type.FullName;
var typeName = type.GetName().Fix();
if (_writeMethodBuilders.TryGetValue(key, out method))
return method;
var methodName = String.Concat(WriteStr, typeName);
method = typeBuilder.DefineMethod(methodName, StaticMethodAttribute,
_voidType, new[] { type, _stringBuilderType });
_writeMethodBuilders[key] = method;
var il = method.GetILGenerator();
if (type.IsPrimitiveType()) {
var nullLabel = il.DefineLabel();
needQuote = needQuote && (type == _stringType || type == _guidType || type == _timeSpanType || type == _dateTimeType || type == _byteArrayType);
if (type == _stringType || type == _objectType) {
il.Emit(OpCodes.Ldarg_0);
if (type == _stringType) {
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Call, _stringOpEquality);
}
il.Emit(OpCodes.Brfalse, nullLabel);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldstr, NullStr);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ret);
il.MarkLabel(nullLabel);
if (needQuote) {
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldstr, QuotChar);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
//il.Emit(OpCodes.Pop);
} else il.Emit(OpCodes.Ldarg_1);
//il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Ldarg_0);
if (type == _objectType)
il.Emit(OpCodes.Callvirt, _objectToString);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
//il.Emit(OpCodes.Pop);
if (needQuote) {
//il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Ldstr, QuotChar);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
} else il.Emit(OpCodes.Pop);
} else {
if (type == _dateTimeType) {
if (needQuote) {
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldstr, QuotChar);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
}
il.Emit(OpCodes.Ldarg_1);
//il.Emit(OpCodes.Ldstr, IsoFormat);
il.Emit(OpCodes.Ldarg_0);
//il.Emit(OpCodes.Box, _dateTimeType);
//il.Emit(OpCodes.Call, _stringFormat);
il.Emit(OpCodes.Call, _useTickFormat ? _generatorDateToString : _generatorDateToISOFormat);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
if (needQuote) {
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldstr, QuotChar);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
}
} else if (type == _byteArrayType) {
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Brtrue, nullLabel);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldstr, NullStr);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ret);
il.MarkLabel(nullLabel);
if (needQuote) {
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldstr, QuotChar);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
}
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, _convertBase64);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
if (needQuote) {
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldstr, QuotChar);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
}
} else if (type == _boolType) {
var boolLocal = il.DeclareLocal(_stringType);
var boolLabel = il.DefineLabel();
il.Emit(OpCodes.Ldstr, "true");
il.Emit(OpCodes.Stloc, boolLocal);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Brtrue, boolLabel);
il.Emit(OpCodes.Ldstr, "false");
il.Emit(OpCodes.Stloc, boolLocal);
il.MarkLabel(boolLabel);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldloc, boolLocal.LocalIndex);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
} else if (type.IsEnum) {
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Conv_I4);
il.Emit(OpCodes.Box, _intType);
il.Emit(OpCodes.Call, _generatorIntToStr);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
} else {
if (needQuote) {
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldstr, QuotChar);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
}
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Box, type);
il.Emit(OpCodes.Callvirt, _objectToString);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
if (needQuote) {
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldstr, QuotChar);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
}
}
}
} else {
WriteSerializeFor(typeBuilder, type, il);
}
il.Emit(OpCodes.Ret);
return method;
}
internal static void WriteSerializeFor(TypeBuilder typeBuilder, Type type, ILGenerator methodIL) {
var conditionLabel = methodIL.DefineLabel();
methodIL.Emit(OpCodes.Ldarg_0);
methodIL.Emit(OpCodes.Brtrue, conditionLabel);
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Ldstr, NullStr);
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend);
methodIL.Emit(OpCodes.Pop);
methodIL.Emit(OpCodes.Ret);
methodIL.MarkLabel(conditionLabel);
if (type.IsClassType()) WritePropertiesFor(typeBuilder, type, methodIL);
else WriteCollection(typeBuilder, type, methodIL);
}
internal static void WriteCollection(TypeBuilder typeBuilder, Type type, ILGenerator il) {
var isDict = type.IsDictionaryType();
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldc_I4_S, isDict ? ObjectOpen : ArrayOpen);
il.Emit(OpCodes.Callvirt, _stringBuilderAppendChar);
il.Emit(OpCodes.Pop);
if (type.IsDictionaryType())
WriteDictionary(typeBuilder, type, il);
else WriteListArray(typeBuilder, type, il);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldc_I4_S, isDict ? ObjectClose : ArrayClose);
il.Emit(OpCodes.Callvirt, _stringBuilderAppendChar);
il.Emit(OpCodes.Pop);
}
internal static void WriteDictionary(TypeBuilder typeBuilder, Type type, ILGenerator il) {
var arguments = type.GetGenericArguments();
var keyType = arguments[0];
var valueType = arguments[1];
var isKeyPrimitive = keyType.IsPrimitiveType();
var isValuePrimitive = valueType.IsPrimitiveType();
var keyValuePairType = _genericKeyValuePairType.MakeGenericType(keyType, valueType);
var enumeratorType = _genericDictionaryEnumerator.MakeGenericType(keyType, valueType);
var enumeratorLocal = il.DeclareLocal(enumeratorType);
var entryLocal = il.DeclareLocal(keyValuePairType);
var startEnumeratorLabel = il.DefineLabel();
var moveNextLabel = il.DefineLabel();
var endEnumeratorLabel = il.DefineLabel();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt,
_genericDictType.MakeGenericType(keyType, valueType).GetMethod("GetEnumerator"));
il.Emit(OpCodes.Stloc_S, enumeratorLocal.LocalIndex);
il.BeginExceptionBlock();
il.Emit(OpCodes.Br, startEnumeratorLabel);
il.MarkLabel(moveNextLabel);
il.Emit(OpCodes.Ldloca_S, enumeratorLocal.LocalIndex);
il.Emit(OpCodes.Call,
enumeratorLocal.LocalType.GetProperty("Current")
.GetGetMethod());
il.Emit(OpCodes.Stloc, entryLocal.LocalIndex);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldstr, QuotChar);
il.Emit(OpCodes.Ldloca, entryLocal.LocalIndex);
il.Emit(OpCodes.Call, keyValuePairType.GetProperty("Key").GetGetMethod());
if (keyType.IsValueType)
il.Emit(OpCodes.Box, keyType);
il.Emit(OpCodes.Ldstr, QuotChar);
il.Emit(OpCodes.Ldstr, Colon);
il.Emit(OpCodes.Call, _stringConcat);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
//il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldloca, entryLocal.LocalIndex);
il.Emit(OpCodes.Call, keyValuePairType.GetProperty("Value").GetGetMethod());
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, WriteSerializeMethodFor(typeBuilder, valueType));
il.MarkLabel(startEnumeratorLabel);
il.Emit(OpCodes.Ldloca_S, enumeratorLocal.LocalIndex);
il.Emit(OpCodes.Call, enumeratorType.GetMethod("MoveNext", MethodBinding));
il.Emit(OpCodes.Brtrue, moveNextLabel);
il.Emit(OpCodes.Leave, endEnumeratorLabel);
il.BeginFinallyBlock();
il.Emit(OpCodes.Ldloca_S, enumeratorLocal.LocalIndex);
il.Emit(OpCodes.Constrained, enumeratorLocal.LocalType);
il.Emit(OpCodes.Callvirt, _iDisposableDispose);
il.EndExceptionBlock();
il.MarkLabel(endEnumeratorLabel);
}
internal static void WriteListArray(TypeBuilder typeBuilder, Type type, ILGenerator il) {
var isArray = type.IsArray;
var itemType = isArray ? type.GetElementType() : type.GetGenericArguments()[0];
var isPrimitive = itemType.IsPrimitiveType();
var itemLocal = il.DeclareLocal(itemType);
var indexLocal = il.DeclareLocal(_intType);
var startLabel = il.DefineLabel();
var endLabel = il.DefineLabel();
var countLocal = il.DeclareLocal(typeof(int));
var diffLocal = il.DeclareLocal(typeof(int));
var checkCountLabel = il.DefineLabel();
if (isArray) {
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldlen);
il.Emit(OpCodes.Conv_I4);
il.Emit(OpCodes.Stloc, countLocal.LocalIndex);
} else {
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, type.GetMethod("get_Count"));
il.Emit(OpCodes.Stloc, countLocal.LocalIndex);
}
il.Emit(OpCodes.Ldloc, countLocal.LocalIndex);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Sub);
il.Emit(OpCodes.Stloc, diffLocal.LocalIndex);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Stloc, indexLocal.LocalIndex);
il.Emit(OpCodes.Br, startLabel);
il.MarkLabel(endLabel);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldloc, indexLocal.LocalIndex);
if (isArray)
il.Emit(OpCodes.Ldelem, itemType);
else
il.Emit(OpCodes.Callvirt, type.GetMethod("get_Item"));
il.Emit(OpCodes.Stloc, itemLocal.LocalIndex);
//il.Emit(OpCodes.Ldarg_0);
if (itemLocal.LocalType == _intType) {
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldloc, itemLocal.LocalIndex);
il.Emit(OpCodes.Call, _generatorIntToStr);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
} else {
il.Emit(OpCodes.Ldloc, itemLocal.LocalIndex);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, WriteSerializeMethodFor(typeBuilder, itemType));
}
il.Emit(OpCodes.Ldloc, indexLocal.LocalIndex);
il.Emit(OpCodes.Ldloc, diffLocal.LocalIndex);
il.Emit(OpCodes.Beq, checkCountLabel);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldc_I4_S, Delimeter);
il.Emit(OpCodes.Callvirt, _stringBuilderAppendChar);
il.Emit(OpCodes.Pop);
il.MarkLabel(checkCountLabel);
il.Emit(OpCodes.Ldloc, indexLocal.LocalIndex);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stloc, indexLocal.LocalIndex);
il.MarkLabel(startLabel);
il.Emit(OpCodes.Ldloc, indexLocal.LocalIndex);
il.Emit(OpCodes.Ldloc, countLocal.LocalIndex);
il.Emit(OpCodes.Blt, endLabel);
}
internal static void WritePropertiesFor(TypeBuilder typeBuilder, Type type, ILGenerator il) {
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldc_I4_S, ObjectOpen);
il.Emit(OpCodes.Callvirt, _stringBuilderAppendChar);
il.Emit(OpCodes.Pop);
var props = type.GetTypeProperties();
var count = props.Count() - 1;
var counter = 0;
foreach (var prop in props) {
var name = prop.Name;
var propType = prop.PropertyType;
var isPrimitive = propType.IsPrimitiveType();
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldstr, String.Concat(QuotChar, name, QuotChar, Colon));
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
if (propType == _intType) {
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, prop.GetGetMethod());
//il.Emit(OpCodes.Box, propType);
il.Emit(OpCodes.Call, _generatorIntToStr);
il.Emit(OpCodes.Callvirt, _stringBuilderAppend);
il.Emit(OpCodes.Pop);
} else {
//il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, prop.GetGetMethod());
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, WriteSerializeMethodFor(typeBuilder, propType));
}
if (counter != count) {
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldc_I4_S, Delimeter);
il.Emit(OpCodes.Callvirt, _stringBuilderAppendChar);
il.Emit(OpCodes.Pop);
}
counter++;
}
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldc_I4_S, ObjectClose);
il.Emit(OpCodes.Callvirt, _stringBuilderAppendChar);
il.Emit(OpCodes.Pop);
}
internal static PhoenixSerializer<T> GetSerializer<T>() {
var type = typeof(T);
return (PhoenixSerializer<T>)GetSerializer(type);
}
internal static object GetSerializer(Type type) {
var serializer = default(object);
if (!_serializers.TryGetValue(type, out serializer)) {
serializer = _serializers[type] = Activator.CreateInstance(Generate(type));
}
return serializer;
}
public static string Serialize<T>(T value) {
lock (_lockObject)
return GetSerializer<T>().Serialize(value);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment