Skip to content

Instantly share code, notes, and snippets.

@rpgmaker
Created February 6, 2012 20:42
Show Gist options
  • Save rpgmaker/1754709 to your computer and use it in GitHub Desktop.
Save rpgmaker/1754709 to your computer and use it in GitHub Desktop.
Generate Class and Properties
static void WriteSerializerClass(ILGenerator il,
MethodInfo getSetGetMethod,
Type type, int tag, LocalBuilder msLocal,
List<Action<ILGenerator>> actions) {
var isDefaultLabel = il.DefineLabel();
var isDict = dictType.IsAssignableFrom(type);
var isList = listType.IsAssignableFrom(type);
var isClass = !isDict && !isList;
var ms2Local = il.DeclareLocal(MemoryStreamType);
var bufferLocal = il.DeclareLocal(ByteArrayType);
var lengthBufferLocal = il.DeclareLocal(ByteArrayType);
il.Emit(OpCodes.Brtrue, isDefaultLabel);
il.Emit(OpCodes.Newobj, MemoryStreamCtor);
il.Emit(OpCodes.Stloc, ms2Local.LocalIndex);
if (isClass) {
var actionList = new List<Action<ILGenerator>>();
if (actions != null) actionList.AddRange(actions);
if (getSetGetMethod != null)
actionList.Add(msIL =>
msIL.Emit(OpCodes.Callvirt, getSetGetMethod));
WriteSerializerProperties(il, type, ms2Local, actionList);
} else {
//WriteSerializerDictionary(il, type, getSetGetMethod, ms2Local,
// actions);
il.Emit(OpCodes.Ldloc, ms2Local.LocalIndex);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Callvirt, getSetGetMethod);
if (isDict)
il.Emit(OpCodes.Call,
WriteDictionaryToMethod.MakeGenericMethod(type));
else
il.Emit(OpCodes.Call,
WriteListToMethod.MakeGenericMethod(type));
}
il.Emit(OpCodes.Ldloc, ms2Local.LocalIndex);
il.Emit(OpCodes.Callvirt, MemoryStreamToArrayMethod);
il.Emit(OpCodes.Stloc_S, bufferLocal.LocalIndex);
il.Emit(OpCodes.Ldloc, ms2Local.LocalIndex);
il.Emit(OpCodes.Callvirt, MemoryStreamDisposeMethod);
il.Emit(OpCodes.Ldloc_S, bufferLocal.LocalIndex);
il.Emit(OpCodes.Ldlen);
il.Emit(OpCodes.Conv_I4);
il.Emit(OpCodes.Call, Int32ToBytesMethod);
il.Emit(OpCodes.Stloc_S, lengthBufferLocal.LocalIndex);
il.Emit(OpCodes.Ldloc, msLocal.LocalIndex);
il.Emit(OpCodes.Ldloc_S, lengthBufferLocal.LocalIndex);
il.Emit(OpCodes.Ldlen);
il.Emit(OpCodes.Conv_I4);
il.Emit(OpCodes.Ldc_I4, tag);
il.Emit(OpCodes.Call, EncodeLengthMethod);
il.Emit(OpCodes.Call, WriteBufferMethod);
il.Emit(OpCodes.Ldloc, msLocal.LocalIndex);
il.Emit(OpCodes.Ldloc_S, lengthBufferLocal.LocalIndex);
il.Emit(OpCodes.Call, WriteBufferMethod);
il.Emit(OpCodes.Ldloc, msLocal.LocalIndex);
il.Emit(OpCodes.Ldloc_S, bufferLocal.LocalIndex);
il.Emit(OpCodes.Call, WriteBufferMethod);
il.MarkLabel(isDefaultLabel);
}
static void WriteSerializerProperties(ILGenerator il, Type type, LocalBuilder msLocal,
List<Action<ILGenerator>> actions) {
var propInfos = type.GetProperties(PropertyBinding)
.Union(type.GetInterfaces()
.SelectMany(it => it.GetProperties(PropertyBinding)))
.Select((p, i) => new { Tag = i + 1, Property = p });
var hashSet = new HashSet<string>();
foreach (var propInfo in propInfos) {
var prop = propInfo.Property;
var propType = prop.PropertyType;
if (hashSet.Contains(prop.Name)) continue;
var getSetGetMethod = prop.GetGetMethod();
il.Emit(OpCodes.Ldarg_1);
if (actions != null)
actions.ForEach(action => action(il));
il.Emit(OpCodes.Callvirt, getSetGetMethod);
il.Emit(OpCodes.Call, IsDefaultMethod.MakeGenericMethod(propType));
if (propType.IsComplexType()) {
WriteSerializerClass(il, getSetGetMethod, propType, propInfo.Tag, msLocal, actions);
continue;
}
var isDefaultLabel = il.DefineLabel();
il.Emit(OpCodes.Brtrue_S, isDefaultLabel);
il.Emit(OpCodes.Ldloc, msLocal.LocalIndex);
il.Emit(OpCodes.Ldarg_1);
if (actions != null)
actions.ForEach(action => action(il));
il.Emit(OpCodes.Callvirt, getSetGetMethod);
il.Emit(OpCodes.Ldc_I4, propInfo.Tag);
il.Emit(OpCodes.Call, WriteBytesMethod.MakeGenericMethod(propType));
il.MarkLabel(isDefaultLabel);
hashSet.Add(prop.Name);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment