private static CodeTypeMember[] CreateEqualityOperatorOverloading(string eigenType, bool isValueType) { var nullGuardNecessary = !isValueType; var equality = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = "operator ==", Parameters = { new CodeParameterDeclarationExpression(eigenType, "left"), new CodeParameterDeclarationExpression(eigenType, "right"), }, ReturnType = new CodeTypeReference(typeof(bool)), }; if (nullGuardNecessary) { equality.Statements.Add( // if (Object.ReferenceEquals(null, left)) return Object.ReferenceEquals(null, right); new CodeConditionStatement( ExpressionBuilder.ObjectReferenceEqualsNull(new CodeArgumentReferenceExpression("left")), new CodeMethodReturnStatement( ExpressionBuilder.ObjectReferenceEqualsNull( new CodeArgumentReferenceExpression("right"))))); } equality.Statements.Add( // return left.Equals(right); new CodeMethodReturnStatement( new CodeMethodInvokeExpression( new CodeArgumentReferenceExpression("left"), "Equals", new CodeExpression[] { new CodeArgumentReferenceExpression("right") }))); var disequality = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Static, Name = "operator !=", Parameters = { new CodeParameterDeclarationExpression(eigenType, "left"), new CodeParameterDeclarationExpression(eigenType, "right"), }, ReturnType = new CodeTypeReference(typeof(bool)), }; if (nullGuardNecessary) { disequality.Statements.Add( // if (Object.ReferenceEquals(null, left)) return !Object.ReferenceEquals(null, right); new CodeConditionStatement( ExpressionBuilder.ObjectReferenceEqualsNull(new CodeArgumentReferenceExpression("left")), new CodeMethodReturnStatement( ExpressionBuilder.Negate( ExpressionBuilder.ObjectReferenceEqualsNull( new CodeArgumentReferenceExpression("right")))))); } disequality.Statements.Add( // return (false == left.Equals(right)); new CodeMethodReturnStatement( new CodeBinaryOperatorExpression( new CodePrimitiveExpression(false), CodeBinaryOperatorType.ValueEquality, new CodeMethodInvokeExpression( new CodeArgumentReferenceExpression("left"), "Equals", new CodeExpression[] { new CodeArgumentReferenceExpression("right") })))); return(new CodeTypeMember[] { equality, disequality }); }
private static CodeBinaryOperatorExpression ComparePropertyValueEqualityExpression(ArrayType propertyType, String propertyName, String otherVariableName) { // TODO: this should probably be a warning in the model if (propertyType.RankSpecifiers.Ranks.Count() > 1) { throw new InvalidOperationException( "Cannot generate equality for Array Types with more than one rank-specifier."); } var rankSpecifier = propertyType.RankSpecifiers.Ranks.Single(); if (rankSpecifier.Dimensions > 1) { throw new InvalidOperationException( "Cannot generate equality for Array Type with more than one dimension"); } // (this.Property.Length == other.Property.Length) // && Enumerable.Zip(a, b, (a, b) => Object.Equals(a, b)).All(areEqual => areEqual); var thisPropertyReference = ExpressionBuilder.ThisPropertyReference(propertyName); var otherPropertyReference = OtherPropertyReference(propertyName, otherVariableName); var bothNull = new CodeBinaryOperatorExpression(CompareToNull(thisPropertyReference), CodeBinaryOperatorType.BooleanAnd, CompareToNull(otherPropertyReference)); var bothNotNull = new CodeBinaryOperatorExpression( ExpressionBuilder.Negate(CompareToNull(thisPropertyReference)), CodeBinaryOperatorType.BooleanAnd, ExpressionBuilder.Negate(CompareToNull(otherPropertyReference))); var sameArrayLength = new CodeBinaryOperatorExpression( new CodePropertyReferenceExpression(thisPropertyReference, "Length"), CodeBinaryOperatorType.ValueEquality, new CodePropertyReferenceExpression(otherPropertyReference, "Length")); var zipExpression = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression( new CodeTypeReferenceExpression(typeof(Enumerable)), "Zip"), thisPropertyReference, otherPropertyReference, new CodeSnippetExpression("(a, b) => Object.Equals(a,b)")); var zipPairwiseEquality = new CodeMethodInvokeExpression( new CodeMethodReferenceExpression( new CodeTypeReferenceExpression(typeof(Enumerable)), "All"), zipExpression, new CodeSnippetExpression("areEqual => areEqual") ); return(new CodeBinaryOperatorExpression( bothNull, CodeBinaryOperatorType.BooleanOr, new CodeBinaryOperatorExpression( bothNotNull, CodeBinaryOperatorType.BooleanAnd, new CodeBinaryOperatorExpression(sameArrayLength, CodeBinaryOperatorType.BooleanAnd, zipPairwiseEquality)))); }
private static CodeTypeMember[] CreateEqualsOverloadingUsingEqualityOperator(string typeName, bool isValueType, IEnumerable <PropertyDeclaration> properties) { // if (ReferenceEquals(null, obj)) return false; // return obj is EmployeeId && Equals((EmployeeId) obj); const string parameterName = "obj"; var objVariableReference = new CodeArgumentReferenceExpression(parameterName); var ifReferenceEqualsNullObjReturnFalse = new CodeConditionStatement( ExpressionBuilder.ObjectReferenceEqualsNull(objVariableReference), new CodeStatement[] { new CodeMethodReturnStatement(new CodePrimitiveExpression(false)) }, new CodeStatement[] { } ); var returnObjIsTypeNameAndThisEqualsObj = new CodeMethodReturnStatement( new CodeBinaryOperatorExpression( CreateTypeIsAssignableFrom(typeName, objVariableReference), CodeBinaryOperatorType.BooleanAnd, new CodeMethodInvokeExpression( new CodeThisReferenceExpression(), "Equals", new CodeCastExpression(typeName, objVariableReference)) )); var equalsObject = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Override, Name = "Equals", Parameters = { new CodeParameterDeclarationExpression(typeof(object), parameterName) }, ReturnType = new CodeTypeReference(typeof(bool)), Statements = { ifReferenceEqualsNullObjReturnFalse, returnObjIsTypeNameAndThisEqualsObj } }; var compareExpressions = from property in properties select EqualityMethodsGenerator.ComparePropertyValueEqualityExpression(property, "other"); var nullGuardSeed = isValueType ? (CodeExpression) new CodePrimitiveExpression(true) : ExpressionBuilder.Negate( ExpressionBuilder.ObjectReferenceEqualsNull( new CodeVariableReferenceExpression("other"))); var comparerExpressionJoinedWithAnd = compareExpressions.Aggregate( nullGuardSeed, (CodeExpression a, CodeExpression b) => new CodeBinaryOperatorExpression(a, CodeBinaryOperatorType.BooleanAnd, b)); var equalsTyped = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Final, Name = "Equals", Parameters = { new CodeParameterDeclarationExpression(new CodeTypeReference(typeName), "other") }, ReturnType = new CodeTypeReference(typeof(bool)), Statements = { // return this == other new CodeMethodReturnStatement(comparerExpressionJoinedWithAnd) } }; return(new CodeTypeMember[] { equalsTyped, equalsObject }); }