Monday, August 28, 2006
I use CodeDom to generate ActiveRecord classes in ActiveWriter. Quite fancy, but gets complicated easily. To generate something like this:

        public override bool Equals(object obj)

        {

            if (obj == this) return true;

            if (obj == null || obj.GetType() != this.GetType()) return false;

            MyCompositeKey test = (MyCompositeKey)obj;

            return (_keyA == test.KeyA || (_keyA != null && _keyA.Equals(test.KeyA))) &&

              (_keyB == test.KeyB || (_keyB != null && _keyB.Equals(test.KeyB)));

        }


you code 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;

        }


Strangely, there's no CodeBinaryOperatorType.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.

9/11/2006 2:18:47 PM UTC
peki Gökhan Abi,

string query = String.Format(
@"
public override bool Equals(object obj)
{
if (obj == this) return true;
if (obj == null || obj.GetType() != this.GetType()) return false;
MyCompositeKey test = (MyCompositeKey)obj;
return ({0} == test.KeyA || ({0} != null && {0}.Equals(test.{0}))) &&
({1} == test.KeyB || ({1} != null && {1}.Equals(test.{1})));
}

", fields[0].Name, fields[1].Name);


bu şekilde yapmak, agilityi k.çından anlamak mıdır? gerek okuyucuyu yormaması, gerek codedom bilmeyenleri koruyup gözetmesi, gerekse daha hızlı çalışması, Oytun'un bana küfretmesini engellemiyor, sen hakem olasın aramıza.

ya tabi CodeTypeMember dönecek olması beni haksız çıkartmak için yeter sebep. ama, hani, bide parser olsa parseden, yada... sustum.
9/11/2006 6:54:37 PM UTC
E tabi, simdi bende bir noktada soyle bir kod var:

case "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}":
_provider = new CSharpCodeProvider();
break;
case "{164B10B9-B200-11D0-8C61-00A0C91E29D5}":
_provider = new VBCodeProvider();
break;

Olayi da
_provider.GenerateCodeFromCompileUnit
ile nihayetlendiriyoruz. Yani IronPhyton desek onu da yapacak neredeyse.

CodeDom'u bilecek bir sey yok, can sikici derecede siradan bir object model yapmis adamlar, Iki F1'le 10 dakkada cozulur. Ama okunaklilik gercekten dedigin gibi.

Requirement'inda sadece c# varsa ne ala. CodeDom'u iste gucte kullanmayabilirim belki ama kendime eglencelik bir projede de varsin azicik karisik olsun. Bir gun biliyon mu derlerse aha buyrun derim.
Gokhan
10/10/2006 6:10:45 AM UTC
Why don't you use Refly from codedom code generation
10/10/2006 12:23:43 PM UTC
In ActiveWriter, I was using parts of a prototype in the beginning. It grew too quickly and it's hart to change right now. But I'm planning (hoping) a rewrite in the future.

Another problem is that, I don't know if Refly is still supported or not. I have seen it in v2 trunk of MbUnit.
Gokhan
Name
E-mail
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):