void CreateCompareMethod(List <PropertySerializationInfo> properties)
        {
            const string        endFalseLabel = "compareFailedLabel";
            DynamicMethodHelper il            = new DynamicMethodHelper(
                "Compare_" + type.Name,
                typeof(bool),
                new Type[] { typeof(object), typeof(object) },
                this.type
                );

            //  Create calls to compare each member
            foreach (PropertySerializationInfo propInfo in properties)
            {
                il.BeginScope();
                propInfo.GenerateCompareIL(il, 0, 1);
                il.EndScope();

                il.GotoIfFalse(endFalseLabel);
            }

            //  Return true if all properties passed (didn't goto endFalseLabel)
            il.PushInt(Convert.ToInt32(true));
            il.Return();

            //  Return false if any properties failed (did goto endFalseLabel)
            il.MarkLabel(endFalseLabel);
            il.PushInt(Convert.ToInt32(false));
            il.Return();

            this.compareMethod = (CompareMethod)il.Compile(typeof(CompareMethod));
        }
		/// <summary>
		/// Generates IL to read a single item from the stream and leaves the result on the stack.
		/// </summary>
		/// <param name="type">The <see cref="Type"/> of item to read.</param>
		/// <param name="args">The arguments for generating the il.</param>
		void GenerateReadTypeIL(Type type, GenerateArgs args)
		{
			MethodInfo method = GetTypeMethod(type, TypeMethodType.Deserialize);
			DynamicMethodHelper il = args.il;
			bool dynamic = IsDynamic && (type.IsValueType == false);

			//  Variable names
			const string valueVar = "_readValue";
			const string dynamicTypeIndexVar = "_typeIndex";
			const string dynamicTypeVar = "_dynamicType";
			const string dynamicTypeNameVar = "_dynamicTypeName";
			const string dynamicTypeResolvedLabel = "_dynamicTypeResolved";
			const string dynamicTypeNotNullLabel = "_dynamicTypeNotNull";
			const string dynamicTypeDoneLabel = "_dynamicTypeDone";

			il.BeginScope();
			{
				if (dynamic)
				{
					il.DeclareLocal(dynamicTypeIndexVar, typeof(byte));
					il.DeclareLocal(valueVar, typeof(object));
					il.DeclareLocal(dynamicTypeNameVar, typeof(string));
					il.DeclareLocal(dynamicTypeVar, typeof(Type));

					//  Read type index
					il.PushLocal(args.streamVar);
					il.CallMethod(GetTypeMethod(typeof(byte), TypeMethodType.Deserialize));
					il.PopLocal(dynamicTypeIndexVar);

					//  if (typeIndex == -1) goto :dynamicInstanceNull
					il.PushLocal(dynamicTypeIndexVar);
					il.PushInt(SerializerHeaders.NullVersion);
					il.GotoIfNotEqual(dynamicTypeNotNullLabel);

					//  return null
					//  goto :dynamicTypeDone
					il.PushNull();
					il.Goto(dynamicTypeDoneLabel);

					//  :dynamicTypeNotNull
					il.MarkLabel(dynamicTypeNotNullLabel);

					//  Get type info for typeIndex
					il.PushLocal(args.nameTableVar);
					il.PushLocal(dynamicTypeIndexVar);
					il.PushLocalAsRef(dynamicTypeVar);
					il.PushLocalAsRef(dynamicTypeNameVar);
					il.CallMethod(typeof(TypeNameTable).GetMethod("GetTypeInfo"));

					//  If (type != null) goto :typeResolved
					il.PushLocal(dynamicTypeVar);
					il.GotoIfTrue(dynamicTypeResolvedLabel);

					//  Call Type.GetType to resolve type. We must do this
					//  in the context of the type being deserialized to
					//  get the appropriate visibility permissions
					il.PushLocal(dynamicTypeNameVar);
					il.PushBool(true);
					il.CallMethod(typeof(Type).GetMethod(
										 "GetType",
										 BindingFlags.Static | BindingFlags.Public,
										 null,
										 new [] { typeof(string), typeof(bool) },
										 null
										 ));
					il.PopLocal(dynamicTypeVar);

					//  Save the resolved type back to the type table so
					//  subsequent instances of the same type don't have to
					//  do it again
					il.PushLocal(args.nameTableVar);
					il.PushLocal(dynamicTypeIndexVar);
					il.PushLocal(dynamicTypeVar);
					il.CallMethod(typeof(TypeNameTable).GetMethod("SetResolvedType"));

					//  :typeResolved
					il.MarkLabel(dynamicTypeResolvedLabel);

					//  Create an empty instance of the resolved type
					il.PushLocal(dynamicTypeVar);
					il.PushBool(true);
					il.CallMethod(typeof(Activator).GetMethod(
										 "CreateInstance",
										 new [] { typeof(Type), typeof(bool) }
										 ));

					il.PopLocal(valueVar);

					//  Call the serializer to read it
					il.PushLocalAsRef(valueVar);
					il.PushArg(args.dataArg);
					il.CallMethod(method);
					il.Pop();

					//  return (baseType)dynamicInstance
					il.PushLocal(valueVar);
					il.Cast(type);

					//  :dynamicTypeDone
					il.MarkLabel(dynamicTypeDoneLabel);

				}
				else if (method.DeclaringType == typeof(IPrimitiveReader))
				{
					//  return reader.ReadXXXX()
					il.PushLocal(args.streamVar);
					il.CallMethod(method);
				}
				else //if (type.IsClass)
				{
					//  Create empty instance of type
					il.DeclareLocal(valueVar, typeof(object));
					if (type.IsClass)
					{
						il.NewObject(valueVar, type, Type.EmptyTypes);
					}

					//  Call the serializer to read it
					il.PushLocalAsRef(valueVar);
					il.PushArg(args.dataArg);
					il.CallMethod(method);
					il.Pop();                       // Ignore return value

					//  return (type)instance
					il.PushLocal(valueVar);
					if (type.IsClass)
					{
						il.Cast(type);
					}
					else
					{
						il.UnboxValueType(type);
					}
				}
			}
			il.EndScope();
		}
		/// <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);
			}
		}
		/// <summary>
		/// Generates IL to write a single value from the stack to the stream
		/// </summary>
		/// <param name="type">Type of the object on the stack</param>
		/// <param name="args">The generate args.</param>
		void GenerateWriteTypeIL(Type type, GenerateArgs args)
		{
			MethodInfo method = GetTypeMethod(type, TypeMethodType.Serialize);
			const string valueVar = "writeValue";
			const string valueDoneLabel = "_writeValueDone";
			DynamicMethodHelper il = args.il;
			bool dynamic = IsDynamic && (type.IsValueType == false);

			il.BeginScope();
			{
				il.DeclareLocal(valueVar, type);
				il.PopLocalFromObject(valueVar);

				if (dynamic)
				{
					const string notNullLabel = "_dynamicNotNull";

					//  If value is a reference type then serialize
					//  NullVersion (-1) and do nothing else. No need to
					//  save a type name or anything. If not null then
					//  add type to name table and write the type byte
					//  before calling serializer to write the instance
					il.PushLocal(valueVar);
					il.GotoIfTrue(notNullLabel);

					il.PushLocal(args.streamVar);
					il.PushInt(-1);
					il.CallMethod(GetTypeMethod(typeof(byte), TypeMethodType.Serialize));
					il.Goto(valueDoneLabel);

					il.MarkLabel(notNullLabel);

					//  push writer for Write(byte) call
					il.PushLocal(args.streamVar);

					//  push nameTable for Add(Type) call
					il.DebugWriteNamedLocal(args.nameTableVar);
					il.PushLocal(args.nameTableVar);

					//  push (object)value
					//  call object.GetType()
					il.PushLocal(valueVar);
					il.Cast(typeof(object));
					il.CallMethod(typeof(object).GetMethod("GetType"));

					//  push this.Version
					il.PushInt(this.Version);

					//  call TypeNameTable.Add(Type, version)
					il.CallMethod(typeof(TypeNameTable).GetMethod("Add", new [] { typeof(Type), typeof(int) }));          //  Return type byte

					//  call IPrimitiveWriter.Write(byte)
					il.CallMethod(GetTypeMethod(typeof(byte), TypeMethodType.Serialize));

				}

				if (method.DeclaringType == typeof(IPrimitiveWriter))
				{
					//  push IPrimitiveWriter       ; arg 1 for method call
					//  push elemValue              ; arg 2 for method call
					il.PushLocal(args.streamVar);
					il.PushLocal(valueVar);
				}
				else
				{
					//  push value
					//  push TypeSerializationArgs
					il.PushLocal(valueVar);
					il.PushArg(args.dataArg);
				}

				il.CallMethod(method);

				if (dynamic)
				{
					il.MarkLabel(valueDoneLabel);
				}
			}
			il.EndScope();

		}
		/// <summary>
		/// Generates IL for serializing the property
		/// </summary>
		/// <param name="args">
		///	<para>The arguments used to generate the il.</para>
		/// </param>
		public void GenerateWriteIL(GenerateArgs args)
		{
			#region Names
			const string loopConditionLabel = "loopStart";
			const string loopEndLabel = "loopEnd";
			const string propVar = "propValue";
			const string elemVar = "elemValue";
			const string instanceVar = "instance";
			const string collectionNotNullLabel = "collectionNotNullLabel";
			const string countVar = "collectionCount";
			const string enumVar = "enumerator";
			const string dictEnumVar = "dictEnumerator";
			const string dictKeyVar = "dictKey";
			const string dictValueVar = "dictValue";
			const string enumerableVar = "enumerable";
			#endregion

			DynamicMethodHelper il = args.il;

			if (this.attribute.WriteMethod != null)
			{
				//  Call custom handler
				MethodInfo method = this.OwnerType.GetMethod(
													 this.attribute.WriteMethod,
													 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy,
													 null,
													 new [] { typeof(IPrimitiveWriter) },
													 null
													 );

				if (method == null)
				{
					throw new ApplicationException(string.Format(
									"Failed to locate method {0}.{1} to write 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);

			//  Get property value and store in local
			if (this.classType != null)
			{
				//  For indexer load the instance itself
				il.PushLocal(instanceVar);
			}
			else if (this.property is PropertyInfo)
			{
				il.PushLocal(instanceVar);
				il.CallMethod(((PropertyInfo)this.property).GetGetMethod(true));
			}
			else // FieldInfo
			{
				//  push instance
				//  load_field
				il.GetField(instanceVar, (FieldInfo)this.property);
			}

			//  store propValue
			il.PopLocal(propVar);

			//  If this is a collection and null then store -1 length
			//  If this is a non-null collection then emit loop code            
			if (IsCollection)
			{
				il.DeclareLocal(countVar, typeof(int));
				il.DeclareLocal(enumVar, typeof(IEnumerator));
				il.DeclareLocal(enumerableVar, typeof(IEnumerable));
				il.DeclareLocal(elemVar, this.elementType);

				//  push propValue
				//  push null
				//  branch_if_equal collectionNullLabel
				//  branch collectionNotNullLabel
				il.PushLocal(propVar);
				il.GotoIfTrue(collectionNotNullLabel);

				//  ; collection is null so write -1
				//  push writer
				//  push -1
				//  call IPrimitiveWriter.Write(int)
				//  goto loopEnd
				il.PushLocal(args.streamVar);
				il.PushInt(-1);
				il.CallMethod(GetTypeMethod(typeof(int), TypeMethodType.Serialize));
				il.Goto(loopEndLabel);

				//  :collectionNotNullLabel
				il.MarkLabel(collectionNotNullLabel);

				//  countVar = collection.Length/Count
				if (IsArray)
				{
					il.CallMethod(propVar, "get_Length");
				}
				else
				{
					il.PushLocal(propVar);
					il.Cast(this.collectionInterfaceType);
					il.CallMethod(this.collectionCountMethod);
				}
				il.PopLocal(countVar);

				//  writer.Write(countVar)
				il.PushLocal(args.streamVar);
				il.PushLocal(countVar);
				il.CallMethod(GetTypeMethod(typeof(int), TypeMethodType.Serialize));

				//  enumerable = propVar
				//  enumVar = enumerable.GetEnumerator()
				il.CopyLocal(propVar, enumerableVar);
				il.CallMethod(enumerableVar, "GetEnumerator");
				il.PopLocal(enumVar);

				if (IsDictionary)
				{
					il.DeclareLocal(dictEnumVar, typeof(IDictionaryEnumerator));
					il.DeclareLocal(dictKeyVar, this.dictionaryKeyType);
					il.DeclareLocal(dictValueVar, this.dictionaryValueType);
					il.CopyLocal(enumVar, dictEnumVar);
				}

				//  :loopConditionLable
				//  if (enumVar.MoveNext == false) goto loopEndLabel
				il.MarkLabel(loopConditionLabel);
				il.CallMethod(enumVar, "MoveNext");
				il.GotoIfFalse(loopEndLabel);

				//  if (!dictionary) elemVar = enumVar.Current
				if (IsDictionary == false)
				{
					il.CallMethod(enumVar, "get_Current");
					il.PopLocalFromObject(elemVar);
				}
			}

			//  For dictionary properties serialize the key and value
			//  For everything else serialize the element as-is
			if (IsDictionary)
			{
				//  push elemValue
				//  call get_Key
				//  serialize key
				il.CallMethod(dictEnumVar, "get_Key");
				this.GenerateWriteTypeIL(this.dictionaryKeyType, args);

				//  push elemValue
				//  call get_Value
				//  serialize value
				il.CallMethod(dictEnumVar, "get_Value");
				GenerateWriteTypeIL(this.dictionaryValueType, args);
			}
			else if (IsCollection)
			{
				//  push elemValue
				//  serialize elemValue
				il.PushLocalAsObject(elemVar);
				GenerateWriteTypeIL(this.elementType, args);
			}
			else
			{
				il.PushLocalAsObject(propVar);
				GenerateWriteTypeIL(this.elementType, args);
			}

			//  Complete loop instructions for collection
			if (IsCollection)
			{
				//  branch loopConditionLabel
				//  :loopEnd
				il.Goto(loopConditionLabel);
				il.MarkLabel(loopEndLabel);
			}
		}
		static void GenerateCompareTypeIL(DynamicMethodHelper il, Type t)
		{
			MethodInfo method = GetTypeMethod(t, TypeMethodType.Compare);

			if ((method == null) && (t.IsPrimitive == false))
			{
				il.Pop();
				il.Pop();
				il.PushInt(1);
				return;
			}

			il.BeginScope();
			{
				const string valX = "x";
				const string valY = "y";
				const string valThis = "_thisX";
				const string trueLabel = "endTrue";
				const string falseLabel = "endFalse";
				const string endLabel = "endCheck";

				il.DeclareLocal(valX, typeof(object));
				il.PopLocal(valX);
				il.DeclareLocal(valY, typeof(object));
				il.PopLocal(valY);

				//  If both null or the same object then return true
				il.PushLocal(valX);
				il.PushLocal(valY);
				il.GotoIfEqual(trueLabel);

				//  Exit false if either value is null
				il.PushLocal(valX);
				il.GotoIfFalse(falseLabel);

				il.PushLocal(valY);
				il.GotoIfFalse(falseLabel);

				//  Both operands are non-null so call the type-specific comparison method
				if (t.IsPrimitive)
				{
					il.PushLocal(valX);
					il.UnboxValueType(t);
					il.PushLocal(valX);
					il.UnboxValueType(t);
					il.CompareEqual();
				}
				else
				{
					Type paramType = method.GetParameters()[0].ParameterType;

					il.DebugWriteLine("Calling " + method);
					if (method.IsStatic)
					{
						il.PushLocal(valX);
						if (paramType.IsValueType) il.UnboxValueType(paramType);
					}
					else
					{
						il.DeclareLocal(valThis, t);
						il.PushLocal(valX);
						il.PopLocalFromObject(valThis);
						il.PushThis(valThis, method);
					}
					il.PushLocal(valY);
					if (paramType.IsValueType) il.UnboxValueType(paramType);
					il.CallMethod(method);
				}
				il.GotoIfFalse(falseLabel);

				il.MarkLabel(trueLabel);
				il.PushInt(1);
				il.Goto(endLabel);

				il.MarkLabel(falseLabel);
				il.DebugWriteLine("The following values are not equal:");
				il.DebugWriteLocal(valX);
				il.DebugWriteLocal(valY);
				il.PushInt(0);

				il.MarkLabel(endLabel);
			}
			il.EndScope();
		}
		public void GenerateCompareIL(DynamicMethodHelper il, int xIndex, int yIndex)
		{
			#region Names
			const string instanceX = "instanceX";
			const string propVarX = "propValueX";
			const string enumerableX = "enumerableX";
			const string enumVarX = "enumX";
			const string dictEnumVarX = "dictEnumX";

			const string instanceY = "instanceY";
			const string propVarY = "propValueY";
			const string enumerableY = "enumerableY";
			const string enumVarY = "enumY";
			const string dictEnumVarY = "dictEnumY";

			const string endFalseLabel = "logBadPropertyLabel";
			const string endTrueLabel = "endTrue";
			const string endLabel = "endLabel";
			const string loopStart = "loopStart";
			const string loopEnd = "loopEnd";
			#endregion

			il.DebugWriteLine("Comparing property " + this.Name);

			il.DeclareLocal(instanceX, this.OwnerType);
			il.PushArg(xIndex);
			il.PopLocal(instanceX);

			il.DeclareLocal(instanceY, this.OwnerType);
			il.PushArg(yIndex);
			il.PopLocal(instanceY);

			il.DeclareLocal(propVarX, this.Type);
			il.DeclareLocal(propVarY, this.Type);

			if (this.classType != null)
			{
				il.CopyLocal(instanceX, propVarX);
				il.CopyLocal(instanceY, propVarY);
			}
			else if (this.property is PropertyInfo)
			{
				PropertyInfo pi = (PropertyInfo)this.property;
				MethodInfo getMethod = pi.GetGetMethod(true);

				il.CallMethod(instanceX, getMethod);
				il.PopLocal(propVarX);
				il.CallMethod(instanceY, getMethod);
				il.PopLocal(propVarY);
			}
			else
			{
				il.GetField(instanceX, this.property as FieldInfo);
				il.PopLocal(propVarX);
				il.GetField(instanceY, this.property as FieldInfo);
				il.PopLocal(propVarY);
			}

			//  For ref types, if both null or the same object then return true
			//  For value types, this is a value comparison
			Type t = IsCollection ? (IsDictionary ? null : this.elementType) : this.Type;
			bool doDefault = true;
			if (t != null && t.IsValueType)
			{
				MethodInfo mi = t.GetMethod("op_Equality", new [] { t, t });
				if (mi != null)
				{
					il.PushLocal(propVarX);
					il.PushLocal(propVarY);
					il.CallMethod(mi);
					il.GotoIfFalse(endTrueLabel);
					doDefault = false;
				}
				else if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
				{
					Type it = t.GetGenericArguments()[0];
					mi = typeof(Nullable).GetMethod("Equals", BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
					mi = mi.MakeGenericMethod(it);

					il.PushLocal(propVarX);
					il.PushLocal(propVarY);
					il.CallMethod(mi);
					il.GotoIfFalse(endTrueLabel);
					doDefault = false;
				}
			}

			if (doDefault)
			{
				il.PushLocal(propVarX);
				il.PushLocal(propVarY);
				il.GotoIfEqual(endTrueLabel);
			}

			if (IsCollection)
			{
				il.DeclareLocal(enumerableX, typeof(IEnumerable));
				il.DeclareLocal(enumVarX, typeof(IEnumerator));
				il.DeclareLocal(enumerableY, typeof(IEnumerable));
				il.DeclareLocal(enumVarY, typeof(IEnumerator));

				il.CopyLocal(propVarX, enumerableX);
				il.CallMethod(enumerableX, "GetEnumerator");
				il.PopLocal(enumVarX);

				il.CopyLocal(propVarY, enumerableX);
				il.CallMethod(enumerableX, "GetEnumerator");
				il.PopLocal(enumVarY);

				if (IsDictionary)
				{
					il.DeclareLocal(dictEnumVarX, typeof(IDictionaryEnumerator));
					il.CopyLocal(enumVarX, dictEnumVarX);
					il.DeclareLocal(dictEnumVarY, typeof(IDictionaryEnumerator));
					il.CopyLocal(enumVarY, dictEnumVarY);
				}

				il.MarkLabel(loopStart);
				il.CallMethod(enumVarX, "MoveNext");
				il.GotoIfFalse(loopEnd);

				il.CallMethod(enumVarY, "MoveNext");
				il.GotoIfFalse(endFalseLabel); // y has less elements than x

				if (IsDictionary)
				{
					il.CallMethod(dictEnumVarX, "get_Key");
					il.CallMethod(dictEnumVarY, "get_Key");
					GenerateCompareTypeIL(il, this.dictionaryKeyType);
					il.GotoIfFalse(endFalseLabel);

					il.CallMethod(dictEnumVarX, "get_Value");
					il.CallMethod(dictEnumVarY, "get_Value");
					GenerateCompareTypeIL(il, this.dictionaryValueType);
					il.GotoIfFalse(endFalseLabel);
				}
				else // if (not dictionary)
				{
					il.CallMethod(enumVarX, "get_Current");
					il.CallMethod(enumVarY, "get_Current");
					GenerateCompareTypeIL(il, this.elementType);
					il.GotoIfFalse(endFalseLabel);
				}

				il.Goto(loopStart);
				il.MarkLabel(loopEnd);

				//  enumVarX has no more elements so enumVarY shouldn't
				//  have any more either
				il.CallMethod(enumVarY, "MoveNext");
				il.GotoIfTrue(endFalseLabel); // count mismatch
			}
			else // if (not collection)
			{
				il.PushLocalAsObject(propVarX);
				il.PushLocalAsObject(propVarY);
				GenerateCompareTypeIL(il, this.Type);
				il.GotoIfFalse(endFalseLabel);
			}

			il.MarkLabel(endTrueLabel);
			//il.DebugWriteLine(string.Format("Property {0} is equal", this.Name));
			il.PushInt(1);
			il.Goto(endLabel);

			//  Log out name of property if not equal
			il.MarkLabel(endFalseLabel);
			il.DebugWriteLine(string.Format("Property {0} is not equal", this.Name));
			il.PushInt(0);  // set success to false

			il.MarkLabel(endLabel);
		}