本文老周就给大伙伴们介绍一下方法参数代码的生成。
    在开始之前,先补充一下上一篇烂文的内容。在上一篇文章中,老周检讨了 MemberAttributes 枚举的用法,老周此前误以为该枚举不能进行按位操作,后来发现是可以的。不过啊,MemberAttributes 枚举有些情况下不那么好弄,最典型的就是要生成抽象类的时候,反正老周试了很久,用MemberAttributes枚举不能顺利生成抽象类。
    这时候,老周想到了 TypeAttributes,然后就试了一下。

    1. CodeTypeDeclaration t = new CodeTypeDeclaration("MyClass");
    2. t.TypeAttributes = System.Reflection.TypeAttributes.Abstract;
    3. CodeMemberProperty pry = new CodeMemberProperty();
    4. pry.Name = "A";
    5. pry.Attributes = MemberAttributes.Abstract | MemberAttributes.Public;
    6. pry.Type = new CodeTypeReference(typeof(string));
    7. t.Members.Add(pry);
    8. CodeDomProvider p = CodeDomProvider.CreateProvider("cs");
    9. p.GenerateCodeFromType(t, Console.Out, null);

    把 TypeAttributes 属性设置为 Abstract ,就可以将类标识为抽象类。而抽象成员则可以将 Attributes 属性直接指定为抽象成员,比如上面例子中的A属性。
    然后生成的代码如下图所示。
    image.png

    下面进入本文的要点——生成方法参数。
    老周的习惯是,示例学习效率高。所以,我不多说理论的东西,来看例子。

    1. CodeMemberMethod m = new CodeMemberMethod();
    2. m.Name = "SetData";
    3. m.Attributes = MemberAttributes.Public | MemberAttributes.Final;
    4. // 参数
    5. CodeParameterDeclarationExpression p1 = new CodeParameterDeclarationExpression();
    6. p1.Name = "name";
    7. p1.Type = new CodeTypeReference(typeof(string));
    8. m.Parameters.Add(p1);
    9. CodeParameterDeclarationExpression p2 = new CodeParameterDeclarationExpression();
    10. p2.Name = "city";
    11. p2.Type = new CodeTypeReference(typeof(string));
    12. m.Parameters.Add(p2);
    13. CodeParameterDeclarationExpression p3 = new CodeParameterDeclarationExpression();
    14. p3.Name = "phone";
    15. p3.Type = new CodeTypeReference(typeof(int));
    16. m.Parameters.Add(p3);
    17. CodeCommentStatement cm = new CodeCommentStatement("方法体");
    18. m.Statements.Add(cm);
    19. CodeDomProvider provider = CodeDomProvider.CreateProvider("cs");
    20. provider.GenerateCodeFromMember(m, Console.Out, null);

    别看这代码貌似有点长,其实就是声明一个方法,然后添加三个参数。参数的声明属于表达式,因此用到CodeParameterDeclarationExpression类,Type属性设置参数的类型。
    示例代码中,CodeCommentStatement表示方法体中包含注释。
    生成的方法如下图所示。
    image.png
    默认情况下,参数为输入参数,我们知道,还有两种方法参数——输出参数、引用传参。
    CodeParameterDeclarationExpression 公开 Direction 属性,专门用于设置参数的方向,输入参数是默认值,因此可以不显式赋值,另外两个值就是Ref和Out。
    下面代码将生成一个带有 out 参数的方法。

    1. CodeMemberMethod m3 = new CodeMemberMethod();
    2. m3.Name = "MakeKey";
    3. // 返回值
    4. m3.ReturnType = new CodeTypeReference(typeof(bool));
    5. // 输入参数
    6. CodeParameterDeclarationExpression pi = new CodeParameterDeclarationExpression(typeof(int), "len");
    7. m3.Parameters.Add(pi);
    8. // 输出参数
    9. CodeParameterDeclarationExpression po = new CodeParameterDeclarationExpression(typeof(byte[]), "res");
    10. po.Direction = FieldDirection.Out; //重点
    11. m3.Parameters.Add(po);
    12. Console.WriteLine("VB 代码:");
    13. CodeDomProvider provider = CodeDomProvider.CreateProvider("vb");
    14. provider.GenerateCodeFromMember(m3, Console.Out, null);
    15. Console.WriteLine("\n\nC# 代码:");
    16. provider = CodeDomProvider.CreateProvider("cs");
    17. provider.GenerateCodeFromMember(m3, Console.Out, null);

    要让参数变为输出参数,就要把 Direction 属性设置为 Out。
    请看结果。
    image.png
    知道如何定义 out 参数,那ref参数就简单了,比如下面例子。

    1. // 定义类型
    2. CodeTypeDeclaration dt = new CodeTypeDeclaration("MySocket");
    3. // 方法成员
    4. CodeMemberMethod mt = new CodeMemberMethod();
    5. mt.Name = "ReadData";
    6. mt.Attributes = MemberAttributes.Public;
    7. // ref 参数
    8. CodeParameterDeclarationExpression pr = new CodeParameterDeclarationExpression(typeof(System.Net.IPEndPoint), "endpoint");
    9. pr.Direction = FieldDirection.Ref;
    10. mt.Parameters.Add(pr);
    11. dt.Members.Add(mt);
    12. CodeDomProvider provider = CodeDomProvider.CreateProvider("cs");
    13. provider.GenerateCodeFromType(dt, Console.Out, null);

    生成代码如下。
    image.png