Skip to content

Instantly share code, notes, and snippets.

@rpgmaker
Created August 13, 2012 04:18
Show Gist options
  • Save rpgmaker/3336912 to your computer and use it in GitHub Desktop.
Save rpgmaker/3336912 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 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 readerLocal = deserializeIL.DeclareLocal(_xmlReaderExType);
deserializeIL.Emit(OpCodes.Ldarg_1);
deserializeIL.Emit(OpCodes.Newobj, _xmlReaderExCtor);
deserializeIL.Emit(OpCodes.Stloc, readerLocal.LocalIndex);
deserializeIL.Emit(OpCodes.Ldloc, readerLocal.LocalIndex);
deserializeIL.Emit(OpCodes.Callvirt, _xmlReaderExRead);
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.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[] { _xmlReaderExType });
_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, LocalBuilder nodeNameLocal, ILGenerator methodIL) {
var isClass = type.IsClass;
var isNodeEndLabel = methodIL.DefineLabel();
var breakLabel = methodIL.DefineLabel();
var isNodeValidLabel = methodIL.DefineLabel();
var readLabel = methodIL.DefineLabel();
var whileLabel = methodIL.DefineLabel();
var readLocal = methodIL.DeclareLocal(_boolType);
var method = WriteReadPropertyMethodFor(typeBuilder, type);
methodIL.Emit(OpCodes.Br, whileLabel);
methodIL.MarkLabel(readLabel);
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Ldloc, nodeNameLocal.LocalIndex);
methodIL.Emit(OpCodes.Call, _generatorIsNodeValid);
methodIL.Emit(OpCodes.Ldc_I4_0);
methodIL.Emit(OpCodes.Ceq);
methodIL.Emit(OpCodes.Brtrue, isNodeValidLabel);
methodIL.Emit(OpCodes.Ldarg_0);
methodIL.Emit(isClass ? OpCodes.Ldloc : OpCodes.Ldloca, valueLocal);
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Callvirt, method);
methodIL.MarkLabel(isNodeValidLabel);
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Ldloc, nodeNameLocal.LocalIndex);
methodIL.Emit(OpCodes.Call, _generatorIsNodeEnd);
methodIL.Emit(OpCodes.Ldc_I4_0);
methodIL.Emit(OpCodes.Ceq);
methodIL.Emit(OpCodes.Brtrue, isNodeEndLabel);
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 CreateReadProperty(TypeBuilder typeBuilder, Type type, ILGenerator methodIL) {
var props = type.GetTypeProperties();
var isClass = type.IsClass;
var nodeNameLocal = methodIL.DeclareLocal(_stringType);
methodIL.Emit(OpCodes.Ldarg_2);
methodIL.Emit(OpCodes.Callvirt, _xmlReaderExElementName);
methodIL.Emit(OpCodes.Stloc, nodeNameLocal.LocalIndex);
foreach (var prop in props) {
var name = prop.Name;
var propType = prop.PropertyType;
var isPrimitive = propType.IsPrimitiveType();
var propLabel = methodIL.DefineLabel();
var method = WriteDeserializeMethodFor(typeBuilder, propType);
methodIL.Emit(OpCodes.Ldloc, nodeNameLocal.LocalIndex);
methodIL.Emit(OpCodes.Ldstr, name);
methodIL.Emit(OpCodes.Call, _stringOpEquality);
methodIL.Emit(OpCodes.Brfalse, propLabel);
if (isClass) methodIL.Emit(OpCodes.Ldarg_1);
else methodIL.Emit(OpCodes.Ldarga, 1);
if (!isPrimitive) methodIL.Emit(OpCodes.Ldarg_0);
methodIL.Emit(OpCodes.Ldarg_2);
methodIL.Emit(isPrimitive ? OpCodes.Call : OpCodes.Callvirt, method);
methodIL.Emit(isClass ? OpCodes.Callvirt : OpCodes.Call, prop.GetSetMethod());
methodIL.Emit(OpCodes.Ret);
methodIL.MarkLabel(propLabel);
}
methodIL.Emit(OpCodes.Ldarg_2);
methodIL.Emit(OpCodes.Ldloc, nodeNameLocal.LocalIndex);
methodIL.Emit(OpCodes.Call, _generatorReadToEndElement);
}
internal static MethodInfo WriteReadPropertyMethodFor(TypeBuilder typeBuilder, Type type) {
MethodInfo method;
var key = type.FullName;
if (_readPropertyMethodBuilders.TryGetValue(key, out method)) return method;
var props = type.GetTypeProperties();
var typeName = type.GetName();
typeName = typeName.Fix();
var methodName = String.Concat(ReadPropertyStr, typeName);
method = typeBuilder.DefineMethod(methodName, MethodAttribute,
_voidType, new[] { type.IsClass ? type : type.MakeByRefType(), _xmlReaderExType });
_readPropertyMethodBuilders[key] = method;
var methodIL = (method as MethodBuilder).GetILGenerator();
CreateReadProperty(typeBuilder, type, methodIL);
methodIL.Emit(OpCodes.Ret);
return method;
}
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.Ldstr, ItemsStr);
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, _xmlReaderExRead);
methodIL.Emit(OpCodes.Pop);
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.Ldstr, ItemsStr);
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, _xmlReaderExRead);
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, _xmlReaderExRead);
methodIL.Emit(OpCodes.Pop);
//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, _xmlReaderExRead);
methodIL.Emit(OpCodes.Pop);
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, _xmlReaderExRead);
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, _xmlReaderExElementName);
methodIL.Emit(OpCodes.Stloc, nodeNameLocal.LocalIndex);
methodIL.Emit(OpCodes.Ldarg_1);
methodIL.Emit(OpCodes.Callvirt, _xmlReaderExRead);
methodIL.Emit(OpCodes.Pop);
if (type.IsClassType())
ReadPropertiesFor(typeBuilder, type, valueLocal, nodeNameLocal, 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