Skip to content

Instantly share code, notes, and snippets.

@rpgmaker
Created July 24, 2012 14:35
Show Gist options
  • Save rpgmaker/3170276 to your computer and use it in GitHub Desktop.
Save rpgmaker/3170276 to your computer and use it in GitHub Desktop.
XmlSerializer Generator (Final - I think)
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 typeName = String.Concat(objTypeName.Fix(), _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);
var writerLocal = serializeIL.DeclareLocal(_xmlWriterType);
var writerSettingLocal = serializeIL.DeclareLocal(_xmlWriterSettingType);
serializeIL.Emit(OpCodes.Ldc_I4, DefaultStringBuilderCapacity);
serializeIL.Emit(OpCodes.Newobj, _stringBuilderCtor);
serializeIL.Emit(OpCodes.Stloc, sbLocal.LocalIndex);
serializeIL.Emit(OpCodes.Newobj, _xmlWriterSettingCtor);
serializeIL.Emit(OpCodes.Stloc, writerSettingLocal.LocalIndex);
serializeIL.Emit(OpCodes.Ldloc, writerSettingLocal.LocalIndex);
serializeIL.Emit(OpCodes.Ldc_I4_1);
serializeIL.Emit(OpCodes.Callvirt, _xmlWriterSettingOmitXmlDeclaration);
serializeIL.Emit(OpCodes.Ldloc, sbLocal.LocalIndex);
serializeIL.Emit(OpCodes.Ldloc, writerSettingLocal.LocalIndex);
serializeIL.Emit(OpCodes.Call, _xmlWriterCreate);
serializeIL.Emit(OpCodes.Stloc, writerLocal.LocalIndex);
if (!isPrimitive) serializeIL.Emit(OpCodes.Ldarg_0);
serializeIL.Emit(OpCodes.Ldarg_1);
serializeIL.Emit(OpCodes.Ldarg_1);
serializeIL.Emit(OpCodes.Call, _objectGetType);
serializeIL.Emit(OpCodes.Call, _generatorGetName);
serializeIL.Emit(OpCodes.Call, _generatorFix);
serializeIL.Emit(OpCodes.Ldloc, writerLocal.LocalIndex);
serializeIL.Emit(isPrimitive ? OpCodes.Call : OpCodes.Callvirt,
WriteSerializeMethodFor(type, objType));
serializeIL.Emit(OpCodes.Ldloc, writerLocal.LocalIndex);
serializeIL.Emit(OpCodes.Callvirt, _xmlWriterFlush);
serializeIL.Emit(OpCodes.Ldloc, writerLocal.LocalIndex);
serializeIL.Emit(OpCodes.Callvirt, _xmlWriterClose);
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, _stringType, _xmlWriterType });
_writeMethodBuilders[key] = method;
var methodIL = method.GetILGenerator();
WriteSerializeFor(typeBuilder, type, 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, ILGenerator methodIL) {
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Ldarg_2);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteStartElement);
var props = type.GetTypeProperties();
foreach (var prop in props) {
var name = prop.Name;
var propType = prop.PropertyType;
var isPrimitive = propType.IsPrimitiveType();
var method = WriteSerializeMethodFor(typeBuilder, propType);
if (!isPrimitive) methodIL.Emit(OpCodes.Ldarg_0);
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Callvirt, prop.GetGetMethod());
if (propType.IsValueType)
methodIL.Emit(OpCodes.Box, propType);
methodIL.Emit(OpCodes.Ldstr, name);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(
isPrimitive ? OpCodes.Call : OpCodes.Callvirt, method);
}
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteEndElement);
}
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_3);
methodIL.Emit(OpCodes.Ldstr, _itemStr);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteStartElement);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Ldstr, _typeStr);
methodIL.Emit(OpCodes.Ldstr, _dictStr);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteAttributeString);
var keyMethod = WriteSerializeMethodFor(typeBuilder, keyType);
if (!isKeyPrimitive) methodIL.Emit(OpCodes.Ldarg_0);
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.Ldstr, _keyStr);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(isKeyPrimitive ? OpCodes.Call : OpCodes.Callvirt,
keyMethod);
var valueMethod = WriteSerializeMethodFor(typeBuilder, valueType);
if (!isValuePrimitive) methodIL.Emit(OpCodes.Ldarg_0);
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.Ldstr, _valueStr);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(isValuePrimitive ? OpCodes.Call : OpCodes.Callvirt,
valueMethod);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteEndElement);
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 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);
var method = WriteSerializeMethodFor(typeBuilder, itemType);
if (!isPrimitive) methodIL.Emit(OpCodes.Ldarg_0);
methodIL.Emit(OpCodes.Ldloc, itemLocal.LocalIndex);
if (itemType.IsValueType)
methodIL.Emit(OpCodes.Box, itemType);
methodIL.Emit(OpCodes.Ldstr, itemType.Name.Fix());
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(isPrimitive ? OpCodes.Call : OpCodes.Callvirt,
method);
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 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);
var method = WriteSerializeMethodFor(typeBuilder, listType);
if (!isPrimitive) methodIL.Emit(OpCodes.Ldarg_0);
methodIL.Emit(OpCodes.Ldloc, entryLocal.LocalIndex);
if (listType.IsValueType)
methodIL.Emit(OpCodes.Box, listType);
methodIL.Emit(OpCodes.Ldstr, listType.Name.Fix());
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(isPrimitive ? OpCodes.Call : OpCodes.Callvirt,
method);
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, ILGenerator methodIL) {
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Ldarg_2);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteStartElement);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Ldstr, _itemsStr);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteStartElement);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Ldstr, _typeStr);
methodIL.Emit(OpCodes.Ldstr, _itemsStr);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteAttributeString);
if (type.IsDictionaryType())
WriteDictionary(typeBuilder, type, methodIL);
else WriteListArray(typeBuilder, type, methodIL);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteEndElement);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteEndElement);
}
internal static void WriteDeserializeFor(TypeBuilder typeBuilder, Type type, ILGenerator methodIL) {
var valueLocal = methodIL.DeclareLocal(type);
var nodeNameLocal = methodIL.DeclareLocal(_stringType);
var isClass = type.IsClass;
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, ILGenerator methodIL) {
var conditionLabel = methodIL.DefineLabel();
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Brtrue, conditionLabel);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Ldarg_2);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteStartElement);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Ldstr, _typeStr);
methodIL.Emit(OpCodes.Ldstr, _nilStr);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteAttributeString);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Callvirt, _xmlWriterWriteEndElement);
methodIL.Emit(OpCodes.Ret);
methodIL.MarkLabel(conditionLabel);
if (type.IsClassType()) WritePropertiesFor(typeBuilder, type, methodIL);
else WriteCollection(typeBuilder, type, methodIL);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment