zoukankan      html  css  js  c++  java
  • 使用codedom自动生成代码

    刚刚接触自动代码生成,便小试牛刀,解决了项目中的一些问题。

    问题:我们的项目分成很多层次,当增加一个方法的时候,会显得异常繁琐,但每个层次之间的调用大同小异,所以尝试使用代码生成。现在假设有Engine, EngineBase,LocalEngine, RemoteEngine,Host等几个类,其定义和关系如下:

     1     public class EngineFacade
     2     {
     3         private EngineBase engine = null;
     4         public EngineFacade(bool isLocalEngine = true)
     5         {
     6             if (isLocalEngine)
     7             {
     8                 engine = new LocalEngine();
     9             }
    10             else
    11             {
    12                 engine = new RemoteEngine();
    13             }
    14         }
    15 
    16         public bool GetCurrentStatus()
    17         {
    18             return true;
    19         }
    20     }
    21 
    22     public abstract class EngineBase
    23     {
    24         public abstract bool GetCurrentStatus();
    25     }
    26 
    27     public class LocalEngine : EngineBase
    28     {
    29         public override bool GetCurrentStatus()
    30         {
    31             return true;
    32         }
    33     }
    34 
    35     public class RemoteEngine : EngineBase
    36     {
    37         private IHost host = null;
    38 
    39         public RemoteEngine()
    40         {
    41             host = new Host();
    42         }
    43 
    44         public override bool GetCurrentStatus()
    45         {
    46             return host.GetCurerntStatus();
    47         }
    48     }
    49 
    50     public interface IHost
    51     {
    52         bool GetCurerntStatus();
    53     }
    54 
    55     public class Host : IHost
    56     {
    57         public bool GetCurerntStatus()
    58         {
    59             return true;
    60         }
    61     }
    层次关系定义

    上诉定义的类会被SampleClient调用:

        public class SampleClient
        {
            public void Test()
            {
                var engine = new EngineFacade(false);
                Console.WriteLine(engine.GetCurrentStatus());
            }
        }
    SampleClient

    如果我们需要增加一个新的方法SetStatus,如何避免额外的体力劳动呢?

    解决方案:使用CodeDom进行动态代码生成。

      1 class CodeGenerator
      2     {
      3         private CodeCompileUnit targetUnit = new CodeCompileUnit();
      4         private CodeTypeDeclaration targetClass = new CodeTypeDeclaration("Test");
      5         private static readonly string targetInstance = "engineInstance";
      6 
      7         public CodeGenerator()
      8         {
      9             CodeNamespace sample = new CodeNamespace("CodeDomTest");
     10             sample.Imports.Add(new CodeNamespaceImport("System"));
     11             targetClass.IsClass = true;
     12             targetClass.TypeAttributes = TypeAttributes.Public;
     13             sample.Types.Add(targetClass);
     14             targetUnit.Namespaces.Add(sample);
     15         }
     16 
     17         public void AddMethod(string name, Type returnType, string comments, CodeExpression codeExpression)
     18         {
     19             CodeMemberMethod method = new CodeMemberMethod();
     20             method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
     21             method.Name = name;
     22             method.ReturnType = new CodeTypeReference(returnType);
     23             method.Comments.Add(new CodeCommentStatement(comments));
     24             CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement();
     25             returnStatement.Expression = codeExpression;
     26             method.Statements.Add(returnStatement);
     27             targetClass.Members.Add(method);
     28         }
     29 
     30         public void AddMethod(string name, Type returnType, string comments, CodeExpression codeExpression, string paraName, Type paraType)
     31         {
     32             CodeMemberMethod method = new CodeMemberMethod();
     33             method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
     34             method.Name = name;
     35             method.ReturnType = new CodeTypeReference(returnType);
     36             method.Comments.Add(new CodeCommentStatement(comments));
     37             method.Parameters.Add(new CodeParameterDeclarationExpression(paraType, paraName));
     38             CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement();
     39             returnStatement.Expression = codeExpression;
     40             method.Statements.Add(returnStatement);
     41             targetClass.Members.Add(method);
     42         }
     43 
     44         public void AddMethod(string name, Type returnType, string comments, CodeExpression codeExpression, List<CodeParameterDeclarationExpression> parameters)
     45         {
     46             CodeMemberMethod method = new CodeMemberMethod();
     47             method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
     48             method.Name = name;
     49             method.ReturnType = new CodeTypeReference(returnType);
     50             method.Comments.Add(new CodeCommentStatement(comments));
     51             method.Parameters.AddRange(parameters.ToArray());
     52             CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement();
     53             returnStatement.Expression = codeExpression;
     54             method.Statements.Add(returnStatement);
     55             targetClass.Members.Add(method);
     56         }
     57 
     58 
     59         public void AddAbstractMethod(string name, Type returnType, string comments)
     60         {
     61             CodeMemberMethod method = new CodeMemberMethod();
     62             method.Attributes = MemberAttributes.Abstract | MemberAttributes.Public;
     63             method.Name = name;
     64             method.ReturnType = new CodeTypeReference(returnType);
     65             method.Comments.Add(new CodeCommentStatement(comments));
     66             targetClass.Members.Add(method);
     67         }
     68 
     69         public void AddAbstractMethod(string name, Type returnType, string comments, string paraName, Type paraType)
     70         {
     71             CodeMemberMethod method = new CodeMemberMethod();
     72             method.Attributes = MemberAttributes.Abstract | MemberAttributes.Public;
     73             method.Name = name;
     74             method.ReturnType = new CodeTypeReference(returnType);
     75             method.Parameters.Add(new CodeParameterDeclarationExpression(paraType, paraName));
     76             method.Comments.Add(new CodeCommentStatement(comments));
     77             targetClass.Members.Add(method);
     78         }
     79 
     80         public void AddField(string name, Type fieldType)
     81         {
     82             CodeMemberField member = new CodeMemberField();
     83             member.Attributes = MemberAttributes.Private;
     84             member.Name = name;
     85             member.Type = new CodeTypeReference(fieldType);
     86             targetClass.Members.Add(member);
     87         }
     88 
     89         public void GenerateCode()
     90         {
     91             CodeDomProvider provider = new CSharpCodeProvider();
     92             CodeGeneratorOptions options = new CodeGeneratorOptions();
     93             options.BracingStyle = "C";
     94             using (StreamWriter streamWriter = new StreamWriter("SampleReactorCode.cs"))
     95             {
     96                 provider.GenerateCodeFromCompileUnit(targetUnit, streamWriter, options);
     97             }
     98         }
     99 
    100         public static void Start()
    101         {
    102             CodeGenerator sample = new CodeGenerator();
    103             Test(sample);
    104             sample.GenerateCode();
    105         }
    106 
    107         private static void Test(CodeGenerator sample)
    108         {
    109             var methodToAdd = "Test";
    110             var returnType = typeof(Dictionary<string, object>);
    111             var paraname = "key";
    112             var paraType = typeof(string);
    113             var parTypes = new Dictionary<string, Type>() { { "no", typeof(int) }, { paraname, paraType } };
    114 
    115             var parameters = GenerateParameters(parTypes);
    116             var parArguments = GenerateParametersArguments(parTypes).ToArray();
    117 
    118             sample.AddMethod(methodToAdd, returnType, "This is for engine facade",
    119                 new CodeMethodInvokeExpression(
    120                     new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), targetInstance),
    121                     methodToAdd, parArguments), parameters);
    122             sample.AddAbstractMethod(methodToAdd, returnType, "This is for engine base", paraname, paraType);
    123             sample.AddMethod(methodToAdd, returnType, "This is for local engine",
    124                 new CodeMethodInvokeExpression(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "scenario"),
    125                     methodToAdd, parArguments), parameters);
    126             sample.AddMethod(methodToAdd, returnType, "This is for remote engine",
    127                 new CodeMethodInvokeExpression(
    128                     new CodeTypeReferenceExpression(new CodeTypeReference("HostProxy")), methodToAdd,
    129                     parArguments), parameters);
    130 
    131             var dump = parArguments.ToList();
    132             parameters.Insert(0, new CodeParameterDeclarationExpression(typeof(string), "engineKey"));
    133             dump.Insert(0, new CodeArgumentReferenceExpression("engineKey"));
    134             parArguments = dump.ToArray();
    135 
    136             sample.AddMethod(methodToAdd, returnType, "This is for host",
    137                 new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("InstanceManager"), methodToAdd, parArguments),
    138                 parameters);
    139 
    140             dump.Insert(0, new CodePrimitiveExpression(methodToAdd));
    141             dump.Insert(0, new CodeArgumentReferenceExpression("host_name"));
    142             parArguments = dump.ToArray();
    143             sample.AddMethod(methodToAdd, returnType, "This is for host",
    144                 new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("host"), string.Format("Invoke<{0}>", returnType.ToString())
    145                     , parArguments), parameters);
    146         }
    147 
    148         private static List<CodeParameterDeclarationExpression> GenerateParameters(Dictionary<string, Type> parameterTypes)
    149         {
    150             return parameterTypes.Select(parameterType => new CodeParameterDeclarationExpression(parameterType.Value, parameterType.Key)).ToList();
    151         }
    152         private static List<CodeExpression> GenerateParametersArguments(Dictionary<string, Type> parameterTypes)
    153         {
    154             return parameterTypes.Select(parameterType => (CodeExpression)new CodeArgumentReferenceExpression(parameterType.Key)).ToList();
    155         }
    156     }
    CodeGenerator

    如何使用CodeDom,请参考动态源代码生成和编译

  • 相关阅读:
    11 并发编程-(线程)-信号量&Event&定时器
    10 并发编程-(线程)-GIL全局解释器锁&死锁与递归锁
    星级评定
    maven课程 项目管理利器-maven 3-5 maven生命周期和插件 4星
    maven课程 项目管理利器-maven 3-4 eclipse安装maven插件和新建maven项目
    maven课程 项目管理利器-maven 3-3 maven中的坐标和仓库
    maven课程 项目管理利器-maven 3-2 maven自动建立目录骨架
    maven课程 项目管理利器-maven 3-1 maven常用的构建命令
    maven课程 项目管理利器-maven 2-2第一个maven案例hellomaven
    maven课程 项目管理利器-maven 1-2maven介绍和环境搭建
  • 原文地址:https://www.cnblogs.com/allanli/p/3593948.html
Copyright © 2011-2022 走看看