/// <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);
			}
		}