x01.CodeBuilder: 生成代码框架

根据 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

posted on 2015-12-07 16:21  x01  阅读(712)  评论(1编辑  收藏  举报

导航