根据 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 type198 199 sb.Append("}"); //end namespace200 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 }
看一看,真是惨不忍睹。这大概就是所谓的意大利面条吧。
源代码下载:https://github.com/chinax01/x01.CodeBuilder
新闻热点
疑难解答