x01.CodeBuilder: 生成代碼框架,java代碼生成框架
根據 Assembly 生成代碼框架。
這是學習 AvalonEdit 的一個副產品。學習時,照著源代碼新建文件夾,新建文件,添加方法與屬性,雖然只是個框架,也要花費大量時間。為什麼不讓它自動生成呢?於是,新建了個控制台程序,一步步添加,一步步顯示,一步步調整。雖然還有許多不完善的地方,但它基本能用了。將 Main 方法略作改動,便成了 Build 方法。為操作方便,加了個 WPF 界面。OK!下一步可參照 ILSpy 來進行改寫,當也是一款不錯的工具吧。限於時間與能力,暫且作罷。
主要代碼如下:

![]()
1 /**
2 * Program.cs (c) 2015 by x01
3 */
4 using System;
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.IO;
8 using System.Linq;
9 using System.Reflection;
10 using System.Text;
11 using System.Text.RegularExpressions;
12 using System.Windows;
13
14 namespace x01.CodeBuilder
15 {
16 public class Test<THllo>
17 {
18
19 }
20 /// <summary>
21 /// Description of Program.
22 /// </summary>
23 public static class BuildHelper
24 {
25 static readonly StringBuilder sb = new StringBuilder();
26 static readonly List<string> usings = new List<string>();
27 static string headerFormat = "/**\n * {0}.cs (c) 2015 by x01\n */\n";
28
29 /// <summary>
30 /// 根據 Assebmly 生成代碼框架。
31 /// </summary>
32 /// <param name="path">程序集路徑名</param>
33 /// <param name="outputDirectory">輸出目錄</param>
34 public static void Build(string path, string outputDirectory)
35 {
36 if (!File.Exists(path)) {
37 throw new Exception("Assembly file not found.");
38 }
39 if (!Directory.Exists(outputDirectory)) {
40 Directory.CreateDirectory(outputDirectory);
41 }
42
43 Assembly assembly = Assembly.LoadFile(path);
44 string assemblyName = assembly.FullName.Split(',')[0];
45
46 string assemblyPath = Path.GetDirectoryName(assembly.Location);
47 foreach (var type in assembly.GetTypes()) {
48 usings.Clear();
49
50 if (!(type.IsEnum || type.IsClass || type.IsInterface || type.IsGenericType)) {
51 continue;
52 }
53
54 string typeName = type.FullName.Replace(assemblyName + ".","");
55
56 string[] typeNameSplits = typeName.Split('.');
57 string fileDirectory = outputDirectory;
58 if (typeNameSplits.Length > 1) {
59 for (int i = 0; i < typeNameSplits.Length - 1; i++) {
60 fileDirectory += "\\" + typeNameSplits[i];
61 if (!Directory.Exists(fileDirectory)) {
62 Directory.CreateDirectory(fileDirectory);
63 }
64 }
65 }
66
67 sb.Clear();
68 int lastDotIndex = type.FullName.LastIndexOf('.');
69 string namespaceName = lastDotIndex > 0 ? type.FullName.Substring(0,lastDotIndex) : type.FullName;
70
71 sb.Append("namespace " + namespaceName + "\n{\n");
72
73 string convertName = ConvertType(type.Name);
74 sb.Append("\t//TODO: " + convertName + "\n");
75
76 if (type.IsPublic) {
77 sb.Append("\tpublic ");
78 } else {
79 sb.Append("\t");
80 }
81
82 if (type.IsAbstract && !type.IsInterface) {
83 sb.Append("abstract ");
84 } else if (type.IsSealed && !type.IsEnum) {
85 sb.Append("sealed ");
86 }
87
88 if (type.IsEnum) {
89 sb.Append("enum ");
90 } else if (type.IsClass) {
91 sb.Append("class ");
92 } else if (type.IsInterface) {
93 sb.Append("interface ");
94 }
95
96 sb.Append(convertName);
97 if (type.BaseType != null && !string.IsNullOrEmpty(type.BaseType.Name)) {
98 sb.Append(" : " + ConvertType(type.BaseType.Name));
99 }
100 sb.Append("\n\t{\n");
101
102 var baseProperties = type.BaseType != null ? type.BaseType.GetProperties() : new PropertyInfo[1];
103 foreach (var property in type.GetProperties()) {
104 if (type.IsEnum) continue;
105
106 var propertyString = property.ToString();
107 bool skip = false;
108 foreach (var bp in baseProperties) {
109 if (bp == null) continue;
110 if (propertyString == bp.ToString()) {
111 skip = true;
112 break;
113 }
114 }
115 if (skip) continue;
116
117 int lastIndex = propertyString.LastIndexOf('.');
118 string propu = string.Empty;
119 if (lastIndex >= 0)
120 propu = propertyString.Substring(0,lastIndex);
121 propu = ConvertType(propu);
122 if (!usings.Contains(propu) && !string.IsNullOrEmpty(propu)) {
123 usings.Add(propu);
124 }
125 string p = propertyString.Substring(lastIndex+1);
126 string[] ps = p.Split(' ');
127 ps[0] = ConvertType(ps[0]) + " ";
128 p = string.Empty;
129 for (int i = 0; i < ps.Length; i++) {
130 p += ps[i];
131 }
132 sb.Append("\t\tpublic " + p + " { get; set; }\n");
133 }
134
135 sb.Append("\n");
136
137 var baseMethods = type.BaseType != null ? type.BaseType.GetMethods() : new MethodInfo[1];
138 foreach (var method in type.GetMethods()) {
139 if (type.IsEnum) continue;
140
141 bool skip = false;
142 foreach (var bm in baseMethods) {
143 if (bm == null) break;
144 if (bm.ToString() == method.ToString()) {
145 skip = true;
146 break;
147 }
148 }
149 if (skip) continue;
150
151 var typeString = method.ReturnType.ToString();
152 if (method.Name.Contains("get_") || method.Name.Contains("set_")
153 || method.Name.Contains("add_") || method.Name.Contains("remove_")) {
154 continue;
155 }
156 int lastIndex = typeString.LastIndexOf('.');
157 string r = string.Empty;
158 if (lastIndex > 0) {
159 string u = typeString.Substring(0,lastIndex);
160 u = ConvertType(u);
161 if (!usings.Contains(u) && !string.IsNullOrEmpty(u)) {
162 usings.Add(u);
163 }
164 r = typeString.Substring(lastIndex+1);
165 } else {
166 r = typeString;
167 }
168 r = ConvertType(r);
169 sb.Append("\t\tpublic " + r + " " + method.Name + "(");
170 int pcount = method.GetParameters().Length;
171 int count = 0;
172 foreach (var parameter in method.GetParameters()) {
173 var paramString = parameter.ParameterType.ToString();
174 int plast = paramString.LastIndexOf('.');
175 string ptype = string.Empty;
176 if (plast > 0) {
177 string pu = paramString.Substring(0, plast);
178 pu = ConvertType(pu);
179 if (!usings.Contains(pu)) {
180 usings.Add(pu);
181 }
182 ptype = paramString.Substring(plast+1);
183 } else {
184 ptype = paramString;
185 }
186 ptype = ConvertType(ptype);
187 count ++;
188 if (pcount == 1 || pcount == count)
189 sb.Append(ptype + " " + parameter.Name);
190 else
191 sb.Append(ptype + " " + parameter.Name + ", ");
192 }
193 sb.Append(")\n");
194 sb.Append("\t\t{\n\t\t\tthrow new NotImplementedException();\n\t\t}\n");
195 }
196
197 sb.Append("\t}\n"); // end type
198
199 sb.Append("}"); //end namespace
200
201 string header = string.Format(headerFormat, convertName);
202 string ustring = header;
203 foreach (var us in usings) {
204 ustring += "using " + us + ";\n";
205 }
206 ustring += "\n" + sb.ToString();
207
208 if (!string.IsNullOrEmpty(convertName)) {
209 string filename = Path.Combine(fileDirectory, convertName) + ".cs";
210 File.WriteAllText(filename, ustring);
211 }
212 }
213 }
214
215 static string ConvertType(string typeName)
216 {
217 int index = typeName.IndexOf('`');
218 if (index >= 0)
219 typeName = typeName.Substring(0,index);
220 index = typeName.IndexOf('+');
221 if (index >= 0)
222 typeName = typeName.Substring(0,index);
223 index = typeName.IndexOf('<');
224 if (index >= 0)
225 typeName = typeName.Substring(0,index);
226 index = typeName.IndexOf(']');
227 if (index >= 0)
228 typeName = typeName.Substring(0, index);
229
230 switch (typeName) {
231 case "Boolean":
232 return "bool";
233 case "Void":
234 return "void";
235 case "Int32":
236 return "int";
237 case "Object":
238 return "object";
239 case "Double":
240 return "double";
241 case "String":
242 return "string";
243 case "Long":
244 return "long";
245 default:
246 break;
247 }
248
249 return typeName;
250 }
251
252 // 測試用的。
253 // static void Main(string[] args)
254 // {
255 // string path = @"E:\Temp\Lab\x01\x01.CodeBuilder\bin\Debug\x01.MelonEdit.exe";
256 // string target = @"E:\Temp\Lab\x01\Output";
257 // Build(path,target);
258 //
259 // Console.ReadKey(true);
260 // }
261 }
262 }
View Code
看一看,真是慘不忍睹。這大概就是所謂的意大利面條吧。
源代碼下載:https://github.com/chinax01/x01.CodeBuilder