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