Skip to content

Instantly share code, notes, and snippets.

@rpgmaker
Created July 18, 2012 15:30
Show Gist options
  • Save rpgmaker/3136941 to your computer and use it in GitHub Desktop.
Save rpgmaker/3136941 to your computer and use it in GitHub Desktop.
XmlSerializer Generator (Contain Serialize logic, missing deserialize logic)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Reflection;
using System.Reflection.Emit;
using System.Xml;
using System.IO;
using System.Collections;
using System.Text.RegularExpressions;
using System.Security;
namespace PServiceBus.Serializer.Xml {
public static class Generator {
const int DefaultStringBuilderCapacity = 1024 * 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;
static readonly ConcurrentDictionary<Type, Type> _types =
new ConcurrentDictionary<Type, Type>();
static readonly string _xmlSerializerStr = "XmlSerializer",
_classStr = "Class", _dllStr = ".dll",
_quote = "`", _iListStr = "IList`1",
iDictStr = "IDictionary`2",
_xmlSerializeStr = "IXmlSerializer.Serialize",
_xmlDeserializeStr = "IXmlSerializer.Deserialize",
_serializeStr = "Serialize", _deserializeStr = "Deserialize",
_writeStr = "Write", _arrayLiteral = "[]",
_arrayStr = "Array", _anonymousBracketStr = "<>",
_typeStr = "type", _nilStr = "nil",
_anonymousStr = "_anonymoustype", _itemsStr = "Items",
_itemStr = "Item", _dictStr = "dict", _keyStr = "Key", _valueStr = "Value",
_capacityStr = "Capacity";
static readonly Type _objectType = typeof(Object),
_serializerType = typeof(IXmlSerializer<>),
_stringType = typeof(String),
_xmlWriterType = typeof(XmlWriter),
_xmlWriterSettingType = typeof(XmlWriterSettings),
_stringBuilderType = typeof(StringBuilder),
_memoryStreamType = typeof(MemoryStream),
_streamWriterType = typeof(StreamWriter),
_voidType = typeof(void),
_intType = typeof(int),
_xmlReaderType = typeof(XmlReader),
_nullableType = typeof(Nullable<>),
_dateTimeType = typeof(DateTime),
_timeSpanType = typeof(TimeSpan),
_decimalType = typeof(decimal),
_byteArray = typeof(byte[]),
_listType = typeof(IList),
_dictType = typeof(IDictionary),
_genericDictType = typeof(Dictionary<,>),
_genericListType = typeof(List<>),
_genericKeyValuePairType = typeof(KeyValuePair<,>),
_genericDictionaryEnumerator =
Type.GetType("System.Collections.Generic.Dictionary`2+Enumerator"),
_genericListEnumerator =
Type.GetType("System.Collections.Generic.List`1+Enumerator"),
_typeType = typeof(Type),
_generatorType = typeof(Generator);
static readonly MethodInfo _stringBuilderToString =
_stringBuilderType.GetMethod("ToString", Type.EmptyTypes),
_iDisposableDispose = typeof(IDisposable).GetMethod("Dispose"),
_objectToString = _objectType.GetMethod("ToString"),
_objectGetType = _objectType.GetMethod("GetType"),
_typeName = _typeType.GetProperty("Name").GetGetMethod(),
_generatorWriteObject = _generatorType.GetMethod("WriteObject", MethodBinding),
_generatorFix = _generatorType.GetMethod("Fix", MethodBinding),
_generatorIsByteArrayType = _generatorType.GetMethod("IsByteArrayType", MethodBinding),
_generatorIsPrimitiveType = _generatorType.GetMethod("IsPrimitiveType", MethodBinding),
_generatorIsClassType = _generatorType.GetMethod("IsClassType", MethodBinding),
_convertToBase64String = typeof(Convert).GetMethod("ToBase64String", new []{ _byteArray }),
_xmlWriterCreate = _xmlWriterType.GetMethod("Create",
MethodBinding, null, new[] { _stringBuilderType, _xmlWriterSettingType }, null),
_xmlWriterFlush = _xmlWriterType.GetMethod("Flush"),
_xmlWriterWriteValue = _xmlWriterType.GetMethod("WriteValue", new []{ _stringType }),
_xmlWriterClose = _xmlWriterType.GetMethod("Close"),
_xmlWriterWriteStartElement = _xmlWriterType.GetMethod("WriteStartElement", new []{ _stringType }),
_xmlWriterWriteAttributeString = _xmlWriterType.GetMethod("WriteAttributeString", new []{ _stringType, _stringType}),
_xmlWriterWriteEndElement = _xmlWriterType.GetMethod("WriteEndElement"),
_streamWriterWrite = _streamWriterType.GetMethod("Write", new[] { _stringType }),
_streamWriterFlush = _streamWriterType.GetMethod("Flush"),
_streamWriterClose = _streamWriterType.GetMethod("Close"),
_memoryStreamClose = typeof(Stream).GetMethod("Close"),
_memoryStreamPosition = _memoryStreamType.GetProperty("Position").GetSetMethod(),
_xmlReaderRead = _xmlReaderType.GetMethod("Read"),
_xmlReaderClose = _xmlReaderType.GetMethod("Close"),
_xmlReaderCreate = _xmlReaderType.GetMethod("Create", MethodBinding, null, new[] { typeof(Stream) }, null),
_xmlWriterSettingOmitXmlDeclaration =
_xmlWriterSettingType.GetProperty("OmitXmlDeclaration").GetSetMethod();
static readonly ConstructorInfo _stringBuilderCtor =
_stringBuilderType.GetConstructor(new[] { typeof(int) }),
_memoryStreamCtor = _memoryStreamType.GetConstructor(Type.EmptyTypes),
_streamWriterCtor = _streamWriterType.GetConstructor(new[] { typeof(Stream) }),
_xmlWriterSettingCtor = _xmlWriterSettingType.GetConstructor(Type.EmptyTypes);
static readonly Type[] _stringParamTypes =
new[] { _stringType };
static readonly Regex _invalidChar = new Regex(@"(>|<|'|""|&)", RegexOptions.Compiled |
RegexOptions.IgnoreCase | RegexOptions.Multiline);
static readonly ConcurrentDictionary<string, MethodBuilder> _writeMethodBuilders =
new ConcurrentDictionary<string, MethodBuilder>();
static readonly ConcurrentDictionary<Type, bool> _primitiveTypes =
new ConcurrentDictionary<Type, bool>();
static readonly ConcurrentDictionary<Type, IEnumerable<PropertyInfo>> _typeProperties =
new ConcurrentDictionary<Type, IEnumerable<PropertyInfo>>();
public static string Fix(this string name) {
return name.Replace(_quote, string.Empty).Replace(_arrayLiteral, _arrayStr).Replace(_anonymousBracketStr, string.Empty);
}
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.IsEnum || key == _byteArray;
});
}
internal static string Escape(this string str) {
if (_invalidChar.IsMatch(str))
return SecurityElement.Escape(str);
return str;
}
public static void WriteObject(object obj, string name, XmlWriter writer) {
writer.WriteStartElement(name);
if (obj == null) writer.WriteAttributeString(_typeStr, _nilStr);
else {
var buffer = obj as byte[];
var str = obj as string;
var value = buffer != null ? Convert.ToBase64String(buffer) :
str != null ? str.Escape() : obj.ToString();
writer.WriteValue(value);
}
writer.WriteEndElement();
}
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();
}
internal static IEnumerable<PropertyInfo> GetTypeProperties(this Type type) {
return _typeProperties.GetOrAdd(type, key => key.GetProperties(PropertyBinding));
}
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.IsGenericType ?
String.Concat(objType.Name,
String.Join(string.Empty,
objType.GetGenericArguments().Select(x => x.FullName))) :
objType.Name;
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.Callvirt, _typeName);
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);//Remove
//ReadObject IL Here
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.IsGenericType ?
String.Concat(type.Name, String.Join(string.Empty,
type.GetGenericArguments().Select(x => x.FullName))) :
type.Name;
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 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());
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());
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);
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 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();
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);
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 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.IsPrimitiveType()) {
methodIL.Emit(OpCodes.Ldarg_1);
if (type.IsValueType)
methodIL.Emit(OpCodes.Box, type);
methodIL.Emit(OpCodes.Ldarg_2);
methodIL.Emit(OpCodes.Ldarg_3);
methodIL.Emit(OpCodes.Call, _generatorWriteObject);
} else {
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