private MethodDefDeclaration InjectEqualsType(TypeDefDeclaration enhancedType, StructuralEqualityAttribute config, ICollection <FieldDefDeclaration> ignoredFields) { IType genericTypeInstance = enhancedType.GetCanonicalGenericInstance(); var existingMethod = enhancedType.Methods.FirstOrDefault <IMethod>(declaration => { return(declaration.Name == "Equals" && declaration.IsPublic() && !declaration.IsStatic && declaration.ParameterCount == 1 && declaration.GetParameterType(0).Equals(genericTypeInstance)); }); if (existingMethod != null) { return(existingMethod.GetMethodDefinition()); } // public virtual bool Equals( Typed other ) var equalsDeclaration = new MethodDefDeclaration { Name = "Equals", Attributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, CallingConvention = CallingConvention.HasThis }; enhancedType.Methods.Add(equalsDeclaration); equalsDeclaration.Parameters.Add(new ParameterDeclaration(0, "other", genericTypeInstance)); equalsDeclaration.ReturnParameter = ParameterDeclaration.CreateReturnParameter(this.booleanType); CompilerGeneratedAttributeHelper.AddCompilerGeneratedAttribute(equalsDeclaration); using (var writer = InstructionWriter.GetInstance()) { var methodBody = MethodBodyCreator.CreateModifiableMethodBody(writer, equalsDeclaration); writer.AttachInstructionSequence(methodBody.PrincipalBlock.AddInstructionSequence()); writer.EmitInstruction(OpCodeNumber.Ldc_I4_0); writer.EmitInstructionLocalVariable(OpCodeNumber.Stloc, methodBody.ReturnVariable); this.InjectReferenceEquals(writer, methodBody, enhancedType); // Writer is either attached to the same sequence (value types) or to a new one which should check the structure. // return base.Equals(other) && this.field1 == other.field1 && ...; if (!config.IgnoreBaseClass && enhancedType.IsValueTypeSafe() != true) { // Find the base method. var baseEqualsMethod = this.instanceEqualsMethod.FindOverride(enhancedType.BaseTypeDef, true) .GetInstance(enhancedType.Module, enhancedType.BaseType.GetGenericContext()); // Do not invoke object.Equals(); if (baseEqualsMethod.DeclaringType.GetTypeDefinition() != this.objectTypeDef) { writer.EmitInstruction(OpCodeNumber.Ldarg_0); writer.EmitInstruction(OpCodeNumber.Ldarg_1); writer.EmitInstructionMethod(OpCodeNumber.Call, baseEqualsMethod); // base.Equals(other) returned false, go to return. writer.EmitBranchingInstruction(OpCodeNumber.Brfalse, methodBody.ReturnSequence); } } foreach (var field in GetFieldsForComparison(enhancedType, ignoredFields)) { this.EmitEqualsField(writer, methodBody, field); } InjectCustomMethods(enhancedType, writer, methodBody); // return true; writer.EmitInstruction(OpCodeNumber.Ldc_I4_1); writer.EmitInstructionLocalVariable(OpCodeNumber.Stloc, methodBody.ReturnVariable); writer.EmitBranchingInstruction(OpCodeNumber.Br, methodBody.ReturnSequence); writer.DetachInstructionSequence(); } return(equalsDeclaration); }