您的位置:首页 > 产品设计 > UI/UE

x01.CodeBuilder: 生成代码框架

2015-12-07 16:21 417 查看
根据 Assembly 生成代码框架。

这是学习 AvalonEdit 的一个副产品。学习时,照着源代码新建文件夹,新建文件,添加方法与属性,虽然只是个框架,也要花费大量时间。为什么不让它自动生成呢?于是,新建了个控制台程序,一步步添加,一步步显示,一步步调整。虽然还有许多不完善的地方,但它基本能用了。将 Main 方法略作改动,便成了 Build 方法。为操作方便,加了个 WPF 界面。OK!下一步可参照 ILSpy 来进行改写,当也是一款不错的工具吧。限于时间与能力,暂且作罢。

主要代码如下:

/**
* Program.cs (c) 2015 by x01
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;

namespace x01.CodeBuilder
{
public class Test<THllo>
{

}
/// <summary>
/// Description of Program.
/// </summary>
public static  class BuildHelper
{
static readonly StringBuilder sb = new StringBuilder();
static readonly List<string> usings = new List<string>();
static string headerFormat = "/**\n * {0}.cs (c) 2015 by x01\n */\n";

/// <summary>
/// 根据 Assebmly 生成代码框架。
/// </summary>
/// <param name="path">程序集路径名</param>
/// <param name="outputDirectory">输出目录</param>
public static void Build(string path, string outputDirectory)
{
if (!File.Exists(path)) {
throw new Exception("Assembly file not found.");
}
if (!Directory.Exists(outputDirectory)) {
Directory.CreateDirectory(outputDirectory);
}

Assembly assembly = Assembly.LoadFile(path);
string assemblyName = assembly.FullName.Split(',')[0];

string assemblyPath = Path.GetDirectoryName(assembly.Location);
foreach (var type in assembly.GetTypes()) {
usings.Clear();

if (!(type.IsEnum || type.IsClass || type.IsInterface || type.IsGenericType)) {
continue;
}

string typeName = type.FullName.Replace(assemblyName + ".","");

string[] typeNameSplits = typeName.Split('.');
string fileDirectory = outputDirectory;
if (typeNameSplits.Length > 1) {
for (int i = 0; i < typeNameSplits.Length - 1; i++) {
fileDirectory += "\\" + typeNameSplits[i];
if (!Directory.Exists(fileDirectory)) {
Directory.CreateDirectory(fileDirectory);
}
}
}

sb.Clear();
int lastDotIndex = type.FullName.LastIndexOf('.');
string namespaceName = lastDotIndex > 0 ? type.FullName.Substring(0,lastDotIndex) : type.FullName;

sb.Append("namespace " + namespaceName + "\n{\n");

string convertName = ConvertType(type.Name);
sb.Append("\t//TODO: " + convertName + "\n");

if (type.IsPublic) {
sb.Append("\tpublic ");
} else {
sb.Append("\t");
}

if (type.IsAbstract && !type.IsInterface) {
sb.Append("abstract ");
} else if (type.IsSealed && !type.IsEnum) {
sb.Append("sealed ");
}

if (type.IsEnum) {
sb.Append("enum ");
} else if (type.IsClass) {
sb.Append("class ");
} else if (type.IsInterface) {
sb.Append("interface ");
}

sb.Append(convertName);
if (type.BaseType != null && !string.IsNullOrEmpty(type.BaseType.Name)) {
sb.Append(" : " + ConvertType(type.BaseType.Name));
}
sb.Append("\n\t{\n");

var baseProperties = type.BaseType != null ? type.BaseType.GetProperties() : new PropertyInfo[1];
foreach (var property in type.GetProperties()) {
if (type.IsEnum) continue;

var propertyString = property.ToString();
bool skip = false;
foreach (var bp in baseProperties) {
if (bp == null) continue;
if (propertyString == bp.ToString()) {
skip = true;
break;
}
}
if (skip) continue;

int lastIndex = propertyString.LastIndexOf('.');
string propu = string.Empty;
if (lastIndex >= 0)
propu = propertyString.Substring(0,lastIndex);
propu = ConvertType(propu);
if (!usings.Contains(propu) && !string.IsNullOrEmpty(propu)) {
usings.Add(propu);
}
string p = propertyString.Substring(lastIndex+1);
string[] ps = p.Split(' ');
ps[0] = ConvertType(ps[0]) + " ";
p = string.Empty;
for (int i = 0; i < ps.Length; i++) {
p += ps[i];
}
sb.Append("\t\tpublic " + p + " { get; set; }\n");
}

sb.Append("\n");

var baseMethods =  type.BaseType != null ? type.BaseType.GetMethods() : new MethodInfo[1];
foreach (var method in type.GetMethods()) {
if (type.IsEnum) continue;

bool skip = false;
foreach (var bm in baseMethods) {
if (bm == null) break;
if (bm.ToString() == method.ToString()) {
skip = true;
break;
}
}
if (skip) continue;

var typeString = method.ReturnType.ToString();
if (method.Name.Contains("get_") || method.Name.Contains("set_")
|| method.Name.Contains("add_") || method.Name.Contains("remove_")) {
continue;
}
int lastIndex = typeString.LastIndexOf('.');
string r = string.Empty;
if (lastIndex > 0) {
string u = typeString.Substring(0,lastIndex);
u = ConvertType(u);
if (!usings.Contains(u) && !string.IsNullOrEmpty(u)) {
usings.Add(u);
}
r = typeString.Substring(lastIndex+1);
} else {
r = typeString;
}
r = ConvertType(r);
sb.Append("\t\tpublic " + r + " " + method.Name + "(");
int pcount = method.GetParameters().Length;
int count = 0;
foreach (var parameter in method.GetParameters()) {
var paramString = parameter.ParameterType.ToString();
int plast = paramString.LastIndexOf('.');
string ptype = string.Empty;
if (plast > 0) {
string pu = paramString.Substring(0, plast);
pu = ConvertType(pu);
if (!usings.Contains(pu)) {
usings.Add(pu);
}
ptype = paramString.Substring(plast+1);
} else {
ptype = paramString;
}
ptype = ConvertType(ptype);
count ++;
if (pcount == 1 || pcount == count)
sb.Append(ptype + " " + parameter.Name);
else
sb.Append(ptype + " " + parameter.Name + ", ");
}
sb.Append(")\n");
sb.Append("\t\t{\n\t\t\tthrow new NotImplementedException();\n\t\t}\n");
}

sb.Append("\t}\n"); // end type

sb.Append("}"); //end namespace

string header = string.Format(headerFormat, convertName);
string ustring = header;
foreach (var us in usings) {
ustring += "using " + us + ";\n";
}
ustring += "\n" + sb.ToString();

if (!string.IsNullOrEmpty(convertName)) {
string filename = Path.Combine(fileDirectory, convertName) + ".cs";
File.WriteAllText(filename, ustring);
}
}
}

static string ConvertType(string typeName)
{
int index = typeName.IndexOf('`');
if (index >= 0)
typeName = typeName.Substring(0,index);
index = typeName.IndexOf('+');
if (index >= 0)
typeName = typeName.Substring(0,index);
index = typeName.IndexOf('<');
if (index >= 0)
typeName = typeName.Substring(0,index);
index = typeName.IndexOf(']');
if (index >= 0)
typeName = typeName.Substring(0, index);

switch (typeName) {
case "Boolean":
return "bool";
case "Void":
return "void";
case "Int32":
return "int";
case "Object":
return "object";
case "Double":
return "double";
case "String":
return "string";
case "Long":
return "long";
default:
break;
}

return typeName;
}

// 测试用的。
//        static void Main(string[] args)
//        {
//            string path = @"E:\Temp\Lab\x01\x01.CodeBuilder\bin\Debug\x01.MelonEdit.exe";
//            string target = @"E:\Temp\Lab\x01\Output";
//            Build(path,target);
//
//            Console.ReadKey(true);
//        }
}
}


View Code
看一看,真是惨不忍睹。这大概就是所谓的意大利面条吧。

源代码下载:https://github.com/chinax01/x01.CodeBuilder
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: