I use CodeDom to generate ActiveRecord classes in ActiveWriter. Quite fancy, but gets complicated easily. To generate something like this:
private CodeTypeMember GetCompositeClassEqualsMethod(string className, List<CodeMemberField> fields)
{
CodeMemberMethod equals = new CodeMemberMethod();
equals.Attributes = MemberAttributes.Public | MemberAttributes.Override;
equals.ReturnType = new CodeTypeReference(typeof(Boolean));
equals.Name = "Equals";
CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(Object), "obj");
equals.Parameters.Add(param);
equals.Statements.Add(new CodeConditionStatement(
new CodeBinaryOperatorExpression(
new CodeFieldReferenceExpression(null, "obj"),
CodeBinaryOperatorType.ValueEquality, new CodeThisReferenceExpression()
), new CodeMethodReturnStatement(new CodePrimitiveExpression(true))
)
);
equals.Statements.Add(new CodeConditionStatement
(
new CodeBinaryOperatorExpression
(
new CodeBinaryOperatorExpression(
new CodeFieldReferenceExpression(null, "obj"),
CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(null)),
CodeBinaryOperatorType.BooleanOr,
new CodeBinaryOperatorExpression(
new CodeMethodInvokeExpression(new CodeFieldReferenceExpression(null, "obj"), "GetType"),
CodeBinaryOperatorType.IdentityInequality,
new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "GetType"))
)
, new CodeMethodReturnStatement(new CodePrimitiveExpression(false))
)
);
equals.Statements.Add(
new CodeVariableDeclarationStatement(new CodeTypeReference(className), "test",
new CodeCastExpression(new CodeTypeReference(className),
new CodeFieldReferenceExpression(null, "obj"))));
List<CodeExpression> expressions = new List<CodeExpression>();
foreach (CodeMemberField field in fields)
{
expressions.Add(
new CodeBinaryOperatorExpression(
//_keyA == test.KeyA
new CodeBinaryOperatorExpression(
new CodeFieldReferenceExpression(null, field.Name),
CodeBinaryOperatorType.ValueEquality,
new CodeFieldReferenceExpression(new CodeFieldReferenceExpression(null, "test"), field.Name)),
CodeBinaryOperatorType.BooleanOr, // ||
new CodeBinaryOperatorExpression(
//_keyA != null
new CodeBinaryOperatorExpression(
new CodeFieldReferenceExpression(null, field.Name),
CodeBinaryOperatorType.IdentityInequality,
new CodePrimitiveExpression(null)
),
CodeBinaryOperatorType.BooleanAnd, // &&
// _keyA.Equals( test.KeyA )
new CodeMethodInvokeExpression(
new CodeFieldReferenceExpression(null, field.Name), "Equals",
new CodeFieldReferenceExpression(
new CodeFieldReferenceExpression(null, "test"), field.Name))
)
)
);
}
CodeExpression expression = null;
if (expressions.Count > 2)
expression =
new CodeBinaryOperatorExpression(expressions[0], CodeBinaryOperatorType.BooleanAnd, GetBooleanAnd(expressions, 1));
else
expression = new CodeBinaryOperatorExpression(expressions[0], CodeBinaryOperatorType.BooleanAnd, expressions[1]);
equals.Statements.Add(new CodeMethodReturnStatement(expression));
return equals;
}
.ValueInequality operator defined. (a==b)==false will do the trick, but how about not having an XOR? I find CodeDom's lack of completeness... disturbing.