/// <summary> /// Generates IL to deserialize the property from a stream /// </summary> /// <param name="args"> /// <para>The arguments used to generate the read il.</para> /// </param> public void GenerateReadIL(GenerateArgs args) { #region Names const string loopStart = "loopStart"; const string loopEnd = "loopEnd"; const string propVar = "propValue"; const string elemVar = "elemVar"; const string indexVar = "loopIndex"; const string instanceVar = "instance"; const string countVar = "count"; const string collectionNotNull = "collectionNotNull"; const string skipObsoleteLabel = "skipObsolete"; #endregion DynamicMethodHelper il = args.il; if (this.attribute.ReadMethod != null) { // Call custom handler MethodInfo method = this.OwnerType.GetMethod( this.attribute.ReadMethod, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, new [] { typeof(IPrimitiveReader) }, null ); if (method == null) { throw new ApplicationException(string.Format( "Failed to locate method {0}.{1} to read property {2}", this.OwnerType.Name, this.attribute.ReadMethod, this.Name )); } il.PushArg(args.instanceArg); il.PushLocal(args.streamVar); il.CallMethod(method); return; } il.DeclareLocal(instanceVar, this.OwnerType); il.DeclareLocal(propVar, this.Type); il.PushArg(args.instanceArg); il.PopLocal(instanceVar); // Create loop for collection types if (IsCollection) { il.DeclareLocal(indexVar, typeof(int)); il.DeclareLocal(countVar, typeof(int)); il.DeclareLocal(elemVar, this.elementType); // countVar = reader.ReadInt32() il.PushLocal(args.streamVar); il.CallMethod(GetTypeMethod(typeof(int), TypeMethodType.Deserialize)); il.PopLocal(countVar); // ; Set prop to null if length < 0 // if (countVar >= 0) goto collectionNotNull il.PushLocal(countVar); il.PushInt(0); il.GotoIfGreaterOrEqual(collectionNotNull); // propVar = null // goto loopEnd il.PushNull(); il.PopLocal(propVar); il.Goto(loopEnd); // :collectionNotNull // if (indexer) // propVar = instanceVar // else if (array) // propVar = new(countVar) // else // propVar = new() // end if il.MarkLabel(collectionNotNull); if (this.classType != null) { il.CopyLocal(instanceVar, propVar); } else if (IsArray) { il.PushLocal(countVar); il.NewObject(propVar, new [] { typeof(int) }); } else { il.NewObject(propVar); } // indexVar = 0 // :loopStart // if (indexVar == countVar) goto loopEnd il.PushInt(0); il.PopLocal(indexVar); il.MarkLabel(loopStart); il.PushLocal(indexVar); il.PushLocal(countVar); il.GotoIfEqual(loopEnd); } // If this is a dictionary then do special handling to add the element // If not then just read the value and use generic code to store it if (IsDictionary) { // propVar.Add(ReadKey(), ReadValue()) il.PushLocal(propVar); il.Cast(this.dictionaryInterfaceType); this.GenerateReadTypeIL(this.dictionaryKeyType, args); this.GenerateReadTypeIL(this.dictionaryValueType, args); il.CallMethod(this.collectionAddMethod); } else { GenerateReadTypeIL(this.elementType, args); il.PopLocal(IsCollection ? elemVar : propVar); } // If this is a collection then add the element and loop if (IsCollection) { switch (this.serializationType & PropertySerializationType.CollectionMask) { case PropertySerializationType.Dictionary: // Already handled break; case PropertySerializationType.Array: // push propValue ; arg 1 (this) // push loopIndex ; arg 2 // push elemValue ; arg 3 // call SetValue il.BeginCallMethod(propVar, "SetValue", new [] { typeof(object), typeof(int) }); il.PushLocalAsObject(elemVar); il.PushLocal(indexVar); il.CallMethod(); break; case PropertySerializationType.List: // push propValue ; arg 1 (this) // push elemValue ; arg 2 // call Add il.PushLocal(propVar); il.Cast(this.collectionInterfaceType); il.PushLocal(elemVar); il.CallMethod(this.collectionAddMethod); break; } // indexVar++ // goto loopStart // :loopEnd il.IncrementLocal(indexVar); il.Goto(loopStart); il.MarkLabel(loopEnd); } // Set property/field value // This isn't required for indexers. if (this.property != null) { if (this.property is PropertyInfo) { il.PushLocal(instanceVar); il.PushLocal(propVar); il.CallMethod(((PropertyInfo)this.property).GetSetMethod(true)); } else // FieldInfo { il.SetField(instanceVar, propVar, (FieldInfo)this.property); } } if (this.attribute.ObsoleteVersion > 0) { il.MarkLabel(skipObsoleteLabel); } }