Created
July 16, 2012 15:17
-
-
Save rpgmaker/3123280 to your computer and use it in GitHub Desktop.
Initial XmlSerializer Generator
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.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