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