Created
July 26, 2012 16:55
-
-
Save rpgmaker/3183199 to your computer and use it in GitHub Desktop.
XmlSerializer Generator (Almost Final)
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.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Reflection; | |
using System.Reflection.Emit; | |
using System.Xml; | |
namespace PServiceBus.Serializer.Xml { | |
public static partial class Generator { | |
public 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 objTypeName = objType.GetName(); | |
var objTypeNameFix = objTypeName.Fix(); | |
var typeName = String.Concat(objTypeNameFix, _xmlSerializerStr); | |
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, _objectType, new[] { genericType }); | |
var serializeMethod = type.DefineMethod(_xmlSerializeStr, MethodAttribute, | |
_stringType, new[] { objType }); | |
var deserializeMethod = type.DefineMethod(_xmlDeserializeStr, MethodAttribute, objType, | |
_stringParamTypes); | |
var serializeIL = serializeMethod.GetILGenerator(); | |
var deserializeIL = deserializeMethod.GetILGenerator(); | |
//Serialize | |
var sbLocal = serializeIL.DeclareLocal(_stringBuilderType); | |
serializeIL.Emit(OpCodes.Call, _generatorGetStringBuilder); | |
serializeIL.Emit(OpCodes.Callvirt, _stringBuilderClear); | |
serializeIL.Emit(OpCodes.Stloc, sbLocal.LocalIndex); | |
if (isPrimitive) { | |
serializeIL.Emit(OpCodes.Ldloc, sbLocal.LocalIndex); | |
serializeIL.Emit(OpCodes.Ldstr, | |
String.Concat(less, objTypeNameFix, greater)); | |
serializeIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
serializeIL.Emit(OpCodes.Pop); | |
serializeIL.Emit(OpCodes.Ldloc, sbLocal.LocalIndex); | |
serializeIL.Emit(OpCodes.Ldarg_1); | |
if (objType.IsValueType) | |
serializeIL.Emit(OpCodes.Box, objType); | |
serializeIL.Emit(OpCodes.Call, _generatorGetWriteString); | |
serializeIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
serializeIL.Emit(OpCodes.Pop); | |
serializeIL.Emit(OpCodes.Ldloc, sbLocal.LocalIndex); | |
serializeIL.Emit(OpCodes.Ldstr, | |
String.Concat(closeTag, objTypeNameFix, greater)); | |
serializeIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
serializeIL.Emit(OpCodes.Pop); | |
} else { | |
serializeIL.Emit(OpCodes.Ldarg_0); | |
serializeIL.Emit(OpCodes.Ldarg_1); | |
serializeIL.Emit(OpCodes.Ldloc, sbLocal.LocalIndex); | |
serializeIL.Emit(OpCodes.Callvirt, WriteSerializeMethodFor(type, objType)); | |
} | |
serializeIL.Emit(OpCodes.Ldloc, sbLocal.LocalIndex); | |
serializeIL.Emit(OpCodes.Callvirt, _stringBuilderToString); | |
serializeIL.Emit(OpCodes.Ret); | |
//Deserialize | |
var msLocal = deserializeIL.DeclareLocal(_memoryStreamType); | |
var swLocal = deserializeIL.DeclareLocal(_streamWriterType); | |
var readerLocal = deserializeIL.DeclareLocal(_xmlReaderType); | |
var returnLocal = deserializeIL.DeclareLocal(objType); | |
deserializeIL.Emit(OpCodes.Newobj, _memoryStreamCtor); | |
deserializeIL.Emit(OpCodes.Stloc, msLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Ldloc, msLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Newobj, _streamWriterCtor); | |
deserializeIL.Emit(OpCodes.Stloc, swLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Ldloc, swLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Ldarg_1); | |
deserializeIL.Emit(OpCodes.Callvirt, _streamWriterWrite); | |
deserializeIL.Emit(OpCodes.Ldloc, swLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Callvirt, _streamWriterFlush); | |
deserializeIL.Emit(OpCodes.Ldloc, msLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Ldc_I8, 0L); | |
deserializeIL.Emit(OpCodes.Callvirt, _memoryStreamPosition); | |
deserializeIL.Emit(OpCodes.Ldloc, msLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Call, _xmlReaderCreate); | |
deserializeIL.Emit(OpCodes.Stloc, readerLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Ldloc, readerLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Callvirt, _xmlReaderRead); | |
deserializeIL.Emit(OpCodes.Pop); | |
if (!isPrimitive) deserializeIL.Emit(OpCodes.Ldarg_0); | |
deserializeIL.Emit(OpCodes.Ldloc, readerLocal.LocalIndex); | |
deserializeIL.Emit(isPrimitive ? OpCodes.Call : OpCodes.Callvirt, | |
WriteDeserializeMethodFor(type, objType)); | |
deserializeIL.Emit(OpCodes.Stloc, returnLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Ldloc, swLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Callvirt, _streamWriterClose); | |
deserializeIL.Emit(OpCodes.Ldloc, msLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Callvirt, _memoryStreamClose); | |
deserializeIL.Emit(OpCodes.Ldloc, readerLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Callvirt, _xmlReaderClose); | |
deserializeIL.Emit(OpCodes.Ldloc, returnLocal.LocalIndex); | |
deserializeIL.Emit(OpCodes.Ret); | |
type.DefineMethodOverride(serializeMethod, | |
genericType.GetMethod(_serializeStr)); | |
type.DefineMethodOverride(deserializeMethod, | |
genericType.GetMethod(_deserializeStr)); | |
returnType = type.CreateType(); | |
_types[objType] = returnType; | |
//assembly.Save(String.Concat(typeName, _dllStr)); | |
return returnType; | |
} | |
internal static MethodInfo WriteSerializeMethodFor(TypeBuilder typeBuilder, Type type) { | |
if (type.IsPrimitiveType()) return _generatorWriteObject; | |
MethodBuilder method; | |
var key = type.FullName; | |
var typeName = type.GetName(); | |
typeName = typeName.Fix(); | |
if (_writeMethodBuilders.TryGetValue(key, out method)) | |
return method; | |
var methodName = String.Concat(_writeStr, typeName); | |
method = typeBuilder.DefineMethod(methodName, MethodAttribute, | |
_voidType, new []{ type, _stringBuilderType }); | |
_writeMethodBuilders[key] = method; | |
var methodIL = method.GetILGenerator(); | |
WriteSerializeFor(typeBuilder, type, typeName, methodIL); | |
methodIL.Emit(OpCodes.Ret); | |
return method; | |
} | |
internal static MethodInfo WriteDeserializeMethodFor(TypeBuilder typeBuilder, Type type) { | |
MethodInfo method; | |
var key = type.FullName; | |
if (_readMethodBuilders.TryGetValue(key, out method)) | |
return method; | |
if (type.IsPrimitiveType()) { | |
method = _readMethodBuilders[key] = | |
_generatorReadObject.MakeGenericMethod(type); | |
return method; | |
} | |
var typeName = type.GetName(); | |
typeName = typeName.Fix(); | |
var methodName = String.Concat(_readStr, typeName); | |
method = typeBuilder.DefineMethod(methodName, MethodAttribute, | |
type, new[] { _xmlReaderType }); | |
_readMethodBuilders[key] = method; | |
var methodIL = (method as MethodBuilder).GetILGenerator(); | |
WriteDeserializeFor(typeBuilder, type, methodIL); | |
methodIL.Emit(OpCodes.Ret); | |
return method; | |
} | |
internal static void ReadPropertiesFor(TypeBuilder typeBuilder, Type type, LocalBuilder valueLocal, ILGenerator methodIL) { | |
var isClass = type.IsClass; | |
var props = type.GetTypeProperties(); | |
foreach (var prop in props) { | |
var name = prop.Name; | |
var propType = prop.PropertyType; | |
var isPrimitive = propType.IsPrimitiveType(); | |
var method = WriteDeserializeMethodFor(typeBuilder, propType); | |
methodIL.Emit(isClass ? OpCodes.Ldloc : OpCodes.Ldloca, | |
valueLocal); | |
if (!isPrimitive) methodIL.Emit(OpCodes.Ldarg_0); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit( | |
isPrimitive ? OpCodes.Call : OpCodes.Callvirt, method); | |
methodIL.Emit(isClass ? OpCodes.Callvirt : OpCodes.Call, | |
prop.GetSetMethod()); | |
} | |
} | |
internal static void WritePropertiesFor(TypeBuilder typeBuilder, Type type, string typeName, ILGenerator methodIL) { | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(less, typeName, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
var props = type.GetTypeProperties(); | |
foreach (var prop in props) { | |
var name = prop.Name; | |
var propType = prop.PropertyType; | |
var isPrimitive = propType.IsPrimitiveType(); | |
if (isPrimitive) { | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(less, name, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Callvirt, prop.GetGetMethod()); | |
if (propType.IsValueType) | |
methodIL.Emit(OpCodes.Box, propType); | |
methodIL.Emit(OpCodes.Call, _generatorGetWriteString); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(closeTag, name, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
} else { | |
methodIL.Emit(OpCodes.Ldarg_0); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Callvirt, prop.GetGetMethod()); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Callvirt, WriteSerializeMethodFor(typeBuilder, propType)); | |
} | |
} | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(closeTag, typeName, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
} | |
internal static void WriteDictionary(TypeBuilder typeBuilder, Type type, ILGenerator methodIL) { | |
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 = methodIL.DeclareLocal(enumeratorType); | |
var entryLocal = methodIL.DeclareLocal(keyValuePairType); | |
var startEnumeratorLabel = methodIL.DefineLabel(); | |
var moveNextLabel = methodIL.DefineLabel(); | |
var endEnumeratorLabel = methodIL.DefineLabel(); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Callvirt, | |
_genericDictType.MakeGenericType(keyType, valueType).GetMethod("GetEnumerator")); | |
methodIL.Emit(OpCodes.Stloc_S, enumeratorLocal.LocalIndex); | |
methodIL.BeginExceptionBlock(); | |
methodIL.Emit(OpCodes.Br, startEnumeratorLabel); | |
methodIL.MarkLabel(moveNextLabel); | |
methodIL.Emit(OpCodes.Ldloca_S, enumeratorLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Call, | |
enumeratorLocal.LocalType.GetProperty("Current") | |
.GetGetMethod()); | |
methodIL.Emit(OpCodes.Stloc, entryLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(less, _itemStr, space, _typeStr, equal, | |
quote, _dictStr, quote, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
if (isKeyPrimitive) { | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(less, _keyStr, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldloca_S, entryLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Call, keyValuePairType.GetProperty("Key").GetGetMethod()); | |
if (keyType.IsValueType) | |
methodIL.Emit(OpCodes.Box, keyType); | |
methodIL.Emit(OpCodes.Call, _generatorGetWriteString); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(closeTag, _keyStr, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
} else { | |
methodIL.Emit(OpCodes.Ldarg_0); | |
methodIL.Emit(OpCodes.Ldloca_S, entryLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Call, keyValuePairType.GetProperty("Key").GetGetMethod()); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Callvirt, WriteSerializeMethodFor(typeBuilder, keyType)); | |
} | |
if (isValuePrimitive) { | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(less, _valueStr, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldloca_S, entryLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Call, keyValuePairType.GetProperty("Value").GetGetMethod()); | |
if (valueType.IsValueType) | |
methodIL.Emit(OpCodes.Box, valueType); | |
methodIL.Emit(OpCodes.Call, _generatorGetWriteString); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(closeTag, _valueStr, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
} else { | |
methodIL.Emit(OpCodes.Ldarg_0); | |
methodIL.Emit(OpCodes.Ldloca_S, entryLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Call, keyValuePairType.GetProperty("Value").GetGetMethod()); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Callvirt, WriteSerializeMethodFor(typeBuilder, valueType)); | |
} | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(closeTag, _itemStr, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.MarkLabel(startEnumeratorLabel); | |
methodIL.Emit(OpCodes.Ldloca_S, enumeratorLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Call, enumeratorType.GetMethod("MoveNext", MethodBinding)); | |
methodIL.Emit(OpCodes.Brtrue, moveNextLabel); | |
methodIL.Emit(OpCodes.Leave, endEnumeratorLabel); | |
methodIL.BeginFinallyBlock(); | |
methodIL.Emit(OpCodes.Ldloca_S, enumeratorLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Constrained, enumeratorLocal.LocalType); | |
methodIL.Emit(OpCodes.Callvirt, _iDisposableDispose); | |
methodIL.EndExceptionBlock(); | |
methodIL.MarkLabel(endEnumeratorLabel); | |
} | |
internal static void WriteArray(TypeBuilder typeBuilder, Type type, ILGenerator methodIL) { | |
var itemType = type.GetElementType(); | |
var name = itemType.Name.Fix(); | |
var isPrimitive = itemType.IsPrimitiveType(); | |
var itemLocal = methodIL.DeclareLocal(itemType); | |
var indexLocal = methodIL.DeclareLocal(_intType); | |
var startLabel = methodIL.DefineLabel(); | |
var endLabel = methodIL.DefineLabel(); | |
methodIL.Emit(OpCodes.Ldc_I4_0); | |
methodIL.Emit(OpCodes.Stloc_S, indexLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Br, startLabel); | |
methodIL.MarkLabel(endLabel); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Ldloc_S, indexLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Ldelem, itemType); | |
methodIL.Emit(OpCodes.Stloc, itemLocal.LocalIndex); | |
if (isPrimitive) { | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(less, name, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldloc, itemLocal.LocalIndex); | |
if (itemType.IsValueType) | |
methodIL.Emit(OpCodes.Box, itemType); | |
methodIL.Emit(OpCodes.Call, _generatorGetWriteString); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(closeTag, name, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
} else { | |
methodIL.Emit(OpCodes.Ldarg_0); | |
methodIL.Emit(OpCodes.Ldloc, itemLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Callvirt, WriteSerializeMethodFor(typeBuilder, itemType)); | |
} | |
methodIL.Emit(OpCodes.Ldloc_S, indexLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Ldc_I4_1); | |
methodIL.Emit(OpCodes.Add); | |
methodIL.Emit(OpCodes.Stloc_S, indexLocal.LocalIndex); | |
methodIL.MarkLabel(startLabel); | |
methodIL.Emit(OpCodes.Ldloc_S, indexLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Ldlen); | |
methodIL.Emit(OpCodes.Conv_I4); | |
methodIL.Emit(OpCodes.Blt, endLabel); | |
} | |
internal static void ReadListArray(TypeBuilder typeBuilder, Type type, LocalBuilder valueLocal, ILGenerator methodIL) { | |
var isArray = type.IsArray; | |
var itemType = isArray ? type.GetElementType() | |
: type.GetGenericArguments()[0]; | |
var isClass = itemType.IsClass; | |
var isPrimitive = itemType.IsPrimitiveType(); | |
var listType = _genericListType.MakeGenericType(itemType); | |
var readLocal = methodIL.DeclareLocal(_boolType); | |
var listLocal = isArray ? methodIL.DeclareLocal(listType) : valueLocal; | |
var isNodeEndLabel = methodIL.DefineLabel(); | |
var breakLabel = methodIL.DefineLabel(); | |
var isNodeValidLabel = methodIL.DefineLabel(); | |
var readLabel = methodIL.DefineLabel(); | |
var whileLabel = methodIL.DefineLabel(); | |
methodIL.Emit(OpCodes.Newobj, listType.GetConstructor(Type.EmptyTypes)); | |
methodIL.Emit(OpCodes.Stloc, listLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Br, whileLabel); | |
methodIL.MarkLabel(readLabel); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Call, _generatorIsNodeValid); | |
methodIL.Emit(OpCodes.Ldc_I4_0); | |
methodIL.Emit(OpCodes.Ceq); | |
methodIL.Emit(OpCodes.Brtrue, isNodeValidLabel); | |
//Process Item | |
methodIL.Emit(OpCodes.Ldloc, listLocal.LocalIndex); | |
if (!isPrimitive) methodIL.Emit(OpCodes.Ldarg_0); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(isPrimitive ? OpCodes.Call : OpCodes.Callvirt, | |
WriteDeserializeMethodFor(typeBuilder, itemType)); | |
methodIL.Emit(OpCodes.Callvirt, listType.GetMethod(_addStr)); | |
//End Process Item | |
methodIL.MarkLabel(isNodeValidLabel); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Ldstr, _itemsStr); | |
methodIL.Emit(OpCodes.Call, _generatorIsNodeEnd); | |
methodIL.Emit(OpCodes.Ldc_I4_0); | |
methodIL.Emit(OpCodes.Ceq); | |
methodIL.Emit(OpCodes.Brtrue, isNodeEndLabel); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Callvirt, _xmlReaderReadEndElement); | |
methodIL.Emit(OpCodes.Br, breakLabel); | |
methodIL.MarkLabel(isNodeEndLabel); | |
methodIL.MarkLabel(whileLabel); | |
methodIL.Emit(OpCodes.Ldc_I4_1); | |
methodIL.Emit(OpCodes.Stloc, readLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Br, readLabel); | |
methodIL.MarkLabel(breakLabel); | |
if (isArray) { | |
methodIL.Emit(OpCodes.Ldloc, listLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Callvirt, | |
listType.GetMethod(_toArrayStr)); | |
methodIL.Emit(OpCodes.Stloc, valueLocal.LocalIndex); | |
} | |
} | |
internal static void ReadDictionary(TypeBuilder typeBuilder, Type type, LocalBuilder valueLocal, ILGenerator methodIL) { | |
var arguments = type.GetGenericArguments(); | |
var keyType = arguments[0]; | |
var isKeyClass = keyType.IsClass; | |
var isKeyPrimitive = keyType.IsPrimitiveType(); | |
var valueType = arguments[1]; | |
var isValueClass = valueType.IsClass; | |
var isValuePrimitive = valueType.IsPrimitiveType(); | |
var dictType = _genericDictType.MakeGenericType(keyType, valueType); | |
var readLocal = methodIL.DeclareLocal(_boolType); | |
var isNodeEndLabel = methodIL.DefineLabel(); | |
var breakLabel = methodIL.DefineLabel(); | |
var isNodeValidLabel = methodIL.DefineLabel(); | |
var readLabel = methodIL.DefineLabel(); | |
var whileLabel = methodIL.DefineLabel(); | |
methodIL.Emit(OpCodes.Newobj, dictType.GetConstructor(Type.EmptyTypes)); | |
methodIL.Emit(OpCodes.Stloc, valueLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Br, whileLabel); | |
methodIL.MarkLabel(readLabel); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Call, _generatorIsNodeValid); | |
methodIL.Emit(OpCodes.Ldc_I4_0); | |
methodIL.Emit(OpCodes.Ceq); | |
methodIL.Emit(OpCodes.Brtrue, isNodeValidLabel); | |
//Process Item | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Callvirt, _xmlReaderRead); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldloc, valueLocal.LocalIndex); | |
if (!isKeyPrimitive) methodIL.Emit(OpCodes.Ldarg_0); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(isKeyPrimitive ? OpCodes.Call : OpCodes.Callvirt, | |
WriteDeserializeMethodFor(typeBuilder, keyType)); | |
if (!isValuePrimitive) methodIL.Emit(OpCodes.Ldarg_0); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(isValuePrimitive ? OpCodes.Call : OpCodes.Callvirt, | |
WriteDeserializeMethodFor(typeBuilder, valueType)); | |
methodIL.Emit(OpCodes.Callvirt, dictType.GetMethod(_setItemStr)); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Callvirt, _xmlReaderReadEndElement); | |
//End Process Item | |
methodIL.MarkLabel(isNodeValidLabel); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Ldstr, _itemsStr); | |
methodIL.Emit(OpCodes.Call, _generatorIsNodeEnd); | |
methodIL.Emit(OpCodes.Ldc_I4_0); | |
methodIL.Emit(OpCodes.Ceq); | |
methodIL.Emit(OpCodes.Brtrue, isNodeEndLabel); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Callvirt, _xmlReaderReadEndElement); | |
methodIL.Emit(OpCodes.Br, breakLabel); | |
methodIL.MarkLabel(isNodeEndLabel); | |
methodIL.MarkLabel(whileLabel); | |
methodIL.Emit(OpCodes.Ldc_I4_1); | |
methodIL.Emit(OpCodes.Stloc, readLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Br, readLabel); | |
methodIL.MarkLabel(breakLabel); | |
} | |
internal static void ReadCollection(TypeBuilder typeBuilder, Type type, LocalBuilder valueLocal, ILGenerator methodIL) { | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Callvirt, _xmlReaderRead); | |
methodIL.Emit(OpCodes.Pop); | |
if (type.IsDictionaryType()) | |
ReadDictionary(typeBuilder, type, valueLocal, methodIL); | |
else ReadListArray(typeBuilder, type, valueLocal, methodIL); | |
} | |
internal static void WriteList(TypeBuilder typeBuilder, Type type, ILGenerator methodIL) { | |
var arguments = type.GetGenericArguments(); | |
var listType = arguments.Length > 0 ? arguments[0] : _objectType; | |
var name = listType.Name.Fix(); | |
var isPrimitive = listType.IsPrimitiveType(); | |
var genericListType = _genericListType.MakeGenericType(listType); | |
var enumeratorType = _genericListEnumerator.MakeGenericType(listType); | |
var enumeratorLocal = methodIL.DeclareLocal(enumeratorType); | |
var entryLocal = methodIL.DeclareLocal(listType); | |
var startEnumeratorLabel = methodIL.DefineLabel(); | |
var moveNextLabel = methodIL.DefineLabel(); | |
var endEnumeratorLabel = methodIL.DefineLabel(); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
if (type.Name == _iListStr) methodIL.Emit(OpCodes.Castclass, genericListType); | |
methodIL.Emit(OpCodes.Callvirt, | |
genericListType.GetMethod("GetEnumerator")); | |
methodIL.Emit(OpCodes.Stloc_S, enumeratorLocal.LocalIndex); | |
methodIL.BeginExceptionBlock(); | |
methodIL.Emit(OpCodes.Br, startEnumeratorLabel); | |
methodIL.MarkLabel(moveNextLabel); | |
methodIL.Emit(OpCodes.Ldloca_S, enumeratorLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Call, | |
enumeratorLocal.LocalType.GetProperty("Current") | |
.GetGetMethod()); | |
methodIL.Emit(OpCodes.Stloc, entryLocal.LocalIndex); | |
if (isPrimitive) { | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(less, name, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldloc, entryLocal.LocalIndex); | |
if (listType.IsValueType) | |
methodIL.Emit(OpCodes.Box, listType); | |
methodIL.Emit(OpCodes.Call, _generatorGetWriteString); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(closeTag, name, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
} else { | |
methodIL.Emit(OpCodes.Ldarg_0); | |
methodIL.Emit(OpCodes.Ldloc, entryLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Callvirt, WriteSerializeMethodFor(typeBuilder, listType)); | |
} | |
methodIL.MarkLabel(startEnumeratorLabel); | |
methodIL.Emit(OpCodes.Ldloca_S, enumeratorLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Call, enumeratorType.GetMethod("MoveNext", MethodBinding)); | |
methodIL.Emit(OpCodes.Brtrue, moveNextLabel); | |
methodIL.Emit(OpCodes.Leave, endEnumeratorLabel); | |
methodIL.BeginFinallyBlock(); | |
methodIL.Emit(OpCodes.Ldloca_S, enumeratorLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Constrained, enumeratorLocal.LocalType); | |
methodIL.Emit(OpCodes.Callvirt, _iDisposableDispose); | |
methodIL.EndExceptionBlock(); | |
methodIL.MarkLabel(endEnumeratorLabel); | |
} | |
internal static void WriteListArray(TypeBuilder typeBuilder, Type type, ILGenerator methodIL) { | |
if (type.IsArray) WriteArray(typeBuilder, type, methodIL); | |
else WriteList(typeBuilder, type, methodIL); | |
} | |
internal static void WriteCollection(TypeBuilder typeBuilder, Type type, string typeName, ILGenerator methodIL) { | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(less, typeName, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(less, _itemsStr, space, _typeStr, equal, | |
quote, _itemsStr, quote, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
if (type.IsDictionaryType()) | |
WriteDictionary(typeBuilder, type, methodIL); | |
else WriteListArray(typeBuilder, type, methodIL); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(closeTag, _itemsStr, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(closeTag, typeName, greater)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
} | |
internal static void WriteDeserializeFor(TypeBuilder typeBuilder, Type type, ILGenerator methodIL) { | |
var valueLocal = methodIL.DeclareLocal(type); | |
var nodeNameLocal = methodIL.DeclareLocal(_stringType); | |
var conditionLocal = methodIL.DefineLabel(); | |
var isClass = type.IsClass; | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Call, _generatorHasNilAttribute); | |
methodIL.Emit(OpCodes.Brfalse_S, conditionLocal); | |
methodIL.Emit(OpCodes.Ldnull); | |
methodIL.Emit(OpCodes.Ret); | |
methodIL.MarkLabel(conditionLocal); | |
if (isClass) { | |
if (!(type.IsDictionaryType() || type.IsListType() || type.IsArray)) { | |
methodIL.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes)); | |
methodIL.Emit(OpCodes.Stloc, valueLocal.LocalIndex); | |
} | |
} else { | |
methodIL.Emit(OpCodes.Ldloca, valueLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Initobj, type); | |
} | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Callvirt, _xmlReaderName); | |
methodIL.Emit(OpCodes.Stloc, nodeNameLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Callvirt, _xmlReaderRead); | |
methodIL.Emit(OpCodes.Pop); | |
if (type.IsClassType()) | |
ReadPropertiesFor(typeBuilder, type, valueLocal, methodIL); | |
else | |
ReadCollection(typeBuilder, type, valueLocal, methodIL); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Ldloc, nodeNameLocal.LocalIndex); | |
methodIL.Emit(OpCodes.Call, _generatorReadToEndElement); | |
methodIL.Emit(isClass ? OpCodes.Ldloc : OpCodes.Ldloca, | |
valueLocal.LocalIndex); | |
} | |
internal static void WriteSerializeFor(TypeBuilder typeBuilder, Type type, string typeName, ILGenerator methodIL) { | |
var conditionLabel = methodIL.DefineLabel(); | |
methodIL.Emit(OpCodes.Ldarg_1); | |
methodIL.Emit(OpCodes.Brtrue, conditionLabel); | |
methodIL.Emit(OpCodes.Ldarg_2); | |
methodIL.Emit(OpCodes.Ldstr, | |
String.Concat(less, typeName, space, _typeStr, equal, | |
quote, _nilStr, quote, space, endTag)); | |
methodIL.Emit(OpCodes.Callvirt, _stringBuilderAppend); | |
methodIL.Emit(OpCodes.Pop); | |
methodIL.Emit(OpCodes.Ret); | |
methodIL.MarkLabel(conditionLabel); | |
if (type.IsClassType()) WritePropertiesFor(typeBuilder, type, typeName, methodIL); | |
else WriteCollection(typeBuilder, type, typeName, methodIL); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment