使用codedom自动生成代码
分类:
IT文章
•
2025-01-06 09:48:37
刚刚接触自动代码生成,便小试牛刀,解决了项目中的一些问题。
问题:我们的项目分成很多层次,当增加一个方法的时候,会显得异常繁琐,但每个层次之间的调用大同小异,所以尝试使用代码生成。现在假设有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
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 }