void CreateDeserializationMethod(List <PropertySerializationInfo> properties) { const string HasNameTableLabel = "_hasNameTable"; const string endLabel = "exitFunction"; const string SkipPropertyLabel = "_skipProperty"; const string BaseSucceededLabel = "_baseSucceeded"; const string SkipLegacyDeserialize = "_skipLegacyDeserialize"; int version = 0; PropertySerializationInfo.GenerateArgs args = new PropertySerializationInfo.GenerateArgs(); args.il = new DynamicMethodHelper( "Deserialize_" + type.Name, null, new Type[] { typeof(object), typeof(int), typeof(TypeSerializationArgs) }, this.type ); args.instanceArg = 0; args.versionArg = 1; args.dataArg = 2; args.streamVar = "_reader"; args.headerVar = "_header"; args.il.DeclareLocal(args.streamVar, typeof(IPrimitiveReader)); args.il.GetField(args.dataArg, typeof(TypeSerializationArgs).GetField("Reader")); args.il.PopLocal(args.streamVar); args.il.DeclareLocal(args.headerVar, typeof(TypeSerializationHeader)); args.il.GetField(args.dataArg, typeof(TypeSerializationArgs).GetField("Header")); args.il.PopLocal(args.headerVar); // Handle legacy deserialization if ((this.LegacyVersion > 0) && (this.MinVersion <= this.LegacyVersion)) { MethodInfo method = this.Type.GetMethod( "Deserialize", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(IPrimitiveReader), typeof(int) }, null ); if (method == null) { throw new ApplicationException(string.Format( "Class {0} specified a legacy version but could not find the Deserialize method", this.Type.Name )); } // // if (dataVersion > legacyVersion) // goto SkipLegacyDeserialize // // call instance.Deserialize(reader, version) // goto endLabel // // :SkipLegacyDeserialize // args.il.PushArg(args.versionArg); args.il.PushInt(this.LegacyVersion); args.il.GotoIfGreater(SkipLegacyDeserialize); args.il.PushArg(args.instanceArg); args.il.PushLocal(args.streamVar); args.il.PushArg(args.versionArg); args.il.CallMethod(method); args.il.Goto(endLabel); args.il.MarkLabel(SkipLegacyDeserialize); } // TypeNameTable _typeNameTable = dataArg.NameTable; // if (_typeNameType == null) // _typeNameType = new TypeNameTable(); // dataArg.NameTable = _typeNameType; args.nameTableVar = "_typeNameTable"; args.il.DeclareLocal(args.nameTableVar, typeof(TypeNameTable)); args.il.GetField(args.dataArg, typeof(TypeSerializationArgs).GetField("NameTable")); args.il.PopLocal(args.nameTableVar); args.il.PushLocal(args.nameTableVar); args.il.GotoIfTrue(HasNameTableLabel); args.il.NewObject(args.nameTableVar); args.il.SetField(args.dataArg, args.nameTableVar, typeof(TypeSerializationArgs).GetField("NameTable")); args.il.BeginCallMethod(args.nameTableVar, "Deserialize", new Type[] { typeof(IPrimitiveReader), typeof(TypeSerializationHeader) }); args.il.PushLocal(args.streamVar); args.il.PushLocal(args.headerVar); args.il.CallMethod(); args.il.BeginCallMethod(args.nameTableVar, "GetSerializationInfo", new Type[] { typeof(SerializationInfo), typeof(int) }); args.il.GetField(args.dataArg, typeof(TypeSerializationArgs).GetField("SerializationInfo")); args.il.PushInt(this.CurrentVersion); args.il.CallMethod(); args.il.MarkLabel(HasNameTableLabel); // If the type automatically serializes its base class // then read it now. This must be done after the derived class // has a chance to load the name table if (this.serializableBaseType != null) { FieldInfo fi = typeof(TypeSerializationArgs).GetField("IsBaseClass"); args.il.PushArg(args.dataArg); args.il.PushBool(true); args.il.SetField(fi); // Set IsBaseClass field to ensure proper type mapping args.il.PushArgAsRef(args.instanceArg); args.il.PushArg(args.dataArg); args.il.CallMethod(PropertySerializationInfo.GetTypeMethod(this.serializableBaseType, PropertySerializationInfo.TypeMethodType.Deserialize)); args.il.GotoIfTrue(BaseSucceededLabel); args.il.PushArg(args.dataArg); args.il.PushBool(false); args.il.SetField(typeof(TypeSerializationArgs).GetField("Succeeded")); args.il.Goto(endLabel); args.il.MarkLabel(BaseSucceededLabel); // Clear IsBaseClass flag args.il.PushArg(args.dataArg); args.il.PushBool(false); args.il.SetField(fi); } // Create calls to deserialize each member foreach (PropertySerializationInfo propInfo in properties) { // If we hit a higher version property then put in // an "if" statement to exit if the serialized version // is lower than the next batch of properties if (propInfo.Version > version) { // push versionParam // push propInfo.Version // branch_if_less_than endLabel ; versionParam < propInfo.Version args.il.PushArg(args.versionArg); args.il.PushInt(propInfo.Version); args.il.GotoIfLess(endLabel); version = propInfo.Version; } args.il.BeginScope(); // If this property is marked obsolete, do not deserialize // it if the data min version is equal to or greater than // the version it was made obsolete in. if (propInfo.ObsoleteVersion > 0) { const string NoHeaderLabel = "_checkObsoleteNoHeader"; const string NotObsoleteLabel = "_notObsolete"; args.il.PushLocal(args.headerVar); args.il.GotoIfFalse(NoHeaderLabel); args.il.CallMethod(args.headerVar, typeof(TypeSerializationHeader).GetProperty("DataMinVersion").GetGetMethod()); args.il.PushInt(propInfo.ObsoleteVersion); args.il.GotoIfGreaterOrEqual(SkipPropertyLabel); args.il.Goto(NotObsoleteLabel); args.il.MarkLabel(NoHeaderLabel); args.il.PushArg(args.versionArg); args.il.PushInt(propInfo.ObsoleteVersion); args.il.GotoIfGreaterOrEqual(SkipPropertyLabel); args.il.MarkLabel(NotObsoleteLabel); } propInfo.GenerateReadIL(args); args.il.MarkLabel(SkipPropertyLabel); args.il.EndScope(); } // :endFunction args.il.MarkLabel(endLabel); args.il.Return(); this.autoDeserializeMethod = (AutoDeserializeMethod)args.il.Compile(typeof(AutoDeserializeMethod)); this.deserializeMethod = DeserializeAutoSerializable; }
void CreateSerializationMethod(List <PropertySerializationInfo> properties) { PropertySerializationInfo.GenerateArgs args = new PropertySerializationInfo.GenerateArgs(); FieldInfo nameTableField = typeof(TypeSerializationArgs).GetField("NameTable"); const string CreatedNameTableVar = "_createdNameTable"; const string HasNameTableLabel = "_hasNameTable"; const string SkipNameTableSerializeLabel = "_skipNameTableSerialize"; const string SerializationInfoVar = "_serializationInfo"; const string SkipUnhandledDataLabel = "_skipUnhandledData"; args.il = new DynamicMethodHelper( "Serialize_" + type.Name, null, new Type[] { typeof(object), typeof(TypeSerializationArgs) }, this.type ); args.instanceArg = 0; args.dataArg = 1; args.streamVar = "_writer"; args.headerVar = "_header"; // IPrimitiveWriter writer = dataArg.Writer; args.il.DeclareLocal(args.streamVar, typeof(IPrimitiveWriter)); args.il.GetField(args.dataArg, typeof(TypeSerializationArgs).GetField("Writer")); args.il.PopLocal(args.streamVar); // TypeSerializationHeader _header = dataArg.Header args.il.DeclareLocal(args.headerVar, typeof(TypeSerializationHeader)); args.il.GetField(args.dataArg, typeof(TypeSerializationArgs).GetField("Header")); args.il.PopLocal(args.headerVar); // SerializationInfo _serializationInfo = dataArg.SerializationInfo args.il.DeclareLocal(SerializationInfoVar, typeof(SerializationInfo)); args.il.GetField(args.dataArg, typeof(TypeSerializationArgs).GetField("SerializationInfo")); args.il.PopLocal(SerializationInfoVar); // bool createdNameTable // TypeNameTable _typeNameTable = dataArg.NameTable; // // if (_typeNameType == null) // { // _typeNameType = new TypeNameTable(); // dataArg.NameTable = _typeNameType; // createdNameTable = true; // } args.il.DeclareLocal(CreatedNameTableVar, typeof(bool)); args.nameTableVar = "_typeNameTable"; args.il.DeclareLocal(args.nameTableVar, typeof(TypeNameTable)); args.il.GetField(args.dataArg, nameTableField); args.il.PopLocal(args.nameTableVar); args.il.PushLocal(args.nameTableVar); args.il.GotoIfTrue(HasNameTableLabel); args.il.PushBool(true); args.il.PopLocal(CreatedNameTableVar); args.il.NewObject(args.nameTableVar); args.il.SetField(args.dataArg, args.nameTableVar, nameTableField); args.il.BeginCallMethod(args.nameTableVar, "Add", new Type[] { typeof(SerializationInfo) }); args.il.PushLocal(SerializationInfoVar); args.il.CallMethod(); args.il.MarkLabel(HasNameTableLabel); // If the type automatically serializes its base class // then write it now. This must be done after the derived class // has a chance to create the name table if (this.serializableBaseType != null) { FieldInfo fi = typeof(TypeSerializationArgs).GetField("IsBaseClass"); args.il.PushArg(args.dataArg); args.il.PushBool(true); args.il.SetField(fi); args.il.PushArg(args.instanceArg); args.il.PushArg(args.dataArg); args.il.CallMethod(PropertySerializationInfo.GetTypeMethod(this.serializableBaseType, PropertySerializationInfo.TypeMethodType.Serialize)); args.il.PushArg(args.dataArg); args.il.PushBool(false); args.il.SetField(fi); } // Create calls to serialize each member foreach (PropertySerializationInfo propInfo in properties) { // Don't serialize this property if it's marked obsolete // and the min version is equal or greater than the // version it was made obsolete in. if ((propInfo.ObsoleteVersion > 0) && (this.MinVersion >= propInfo.ObsoleteVersion)) { continue; } args.il.BeginScope(); propInfo.GenerateWriteIL(args); args.il.EndScope(); } if (this.IsInline == false) { // Write saved unhandled data if current version is lower // than the data we original deserialized from args.il.PushInt(this.CurrentVersion); args.il.CallMethod(args.headerVar, typeof(TypeSerializationHeader).GetProperty("DataVersion").GetGetMethod()); args.il.GotoIfGreaterOrEqual(SkipUnhandledDataLabel); args.il.BeginCallMethod(args.streamVar, "Write", new Type[] { typeof(byte[]) }); args.il.CallMethod(SerializationInfoVar, typeof(SerializationInfo).GetProperty("UnhandledData").GetGetMethod()); args.il.CallMethod(); args.il.MarkLabel(SkipUnhandledDataLabel); // Update header with actual data length args.il.BeginCallMethod(args.headerVar, "UpdateDataLength", new Type[] { typeof(IPrimitiveWriter) }); args.il.PushLocal(args.streamVar); args.il.CallMethod(); // if (createdNameTable) // { // _typeNameTable.Serialize(); -- Will do nothing if the table is empty // } args.il.PushLocal(CreatedNameTableVar); args.il.GotoIfFalse(SkipNameTableSerializeLabel); args.il.BeginCallMethod(args.nameTableVar, "Serialize", new Type[] { typeof(IPrimitiveWriter) }); args.il.PushLocal(args.streamVar); args.il.CallMethod(); args.il.MarkLabel(SkipNameTableSerializeLabel); } args.il.Return(); this.autoSerializeMethod = (AutoSerializeMethod)args.il.Compile(typeof(AutoSerializeMethod)); this.serializeMethod = SerializeAutoSerializable; }