Skip to content

Instantly share code, notes, and snippets.

@rpgmaker
Created July 16, 2012 15:17
Show Gist options
  • Save rpgmaker/3123280 to your computer and use it in GitHub Desktop.
Save rpgmaker/3123280 to your computer and use it in GitHub Desktop.
Initial XmlSerializer Generator
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;
namespace PServiceBus.Serializer.Xml {
public class Generator {
static readonly ConcurrentDictionary<Type, Type> _types =
new ConcurrentDictionary<Type, Type>();
static readonly string _xmlSerializerStr = "XmlSerializer",
_classStr = "Class", _dllStr = ".dll",
_xmlSerializeStr = "IXmlSerializer.Serialize",
_xmlDeserializeStr = "IXmlSerializer.Deserialize",
_serializeStr = "Serialize", _deserializeStr = "Deserialize";
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),
_xmlReaderType = typeof(XmlReader);
static readonly MethodInfo _stringBuilderToString =
_stringBuilderType.GetMethod("ToString", Type.EmptyTypes),
_xmlWriterCreate = _xmlWriterType.GetMethod("Create",
MethodBinding, null, new[] { _stringBuilderType, _xmlWriterSettingType }, null),
_xmlWriterFlush = _xmlWriterType.GetMethod("Flush"),
_xmlWriterClose = _xmlWriterType.GetMethod("Close"),
_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 };
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;
public static Type Generate(Type objType) {
var returnType = default(Type);
if (_types.TryGetValue(objType, out returnType))
return returnType;
var genericType = _serializerType.MakeGenericType(objType);
var typeName = String.Join(objType.Name, _xmlSerializerStr);
var asmName = String.Join(typeName, _classStr);
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName(asmName) {
Version = new Version(1, 0, 0, 0) },
AssemblyBuilderAccess.RunAndSave);
var module = assembly.DefineDynamicModule(String.Join(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);
//WriteObject IL Here
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.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.Ldarg_1);
deserializeIL.Emit(OpCodes.Ldloc, swLocal.LocalIndex);
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_I4_0);
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);
//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));
return returnType;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment