Created
October 21, 2013 05:33
-
-
Save rpgmaker/7079123 to your computer and use it in GitHub Desktop.
JSON Serializer First Draft
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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