根据 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(',')[]; 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 > ) {
for (int i = ; i < typeNameSplits.Length - ; i++) {
fileDirectory += "\\" + typeNameSplits[i];
if (!Directory.Exists(fileDirectory)) {
Directory.CreateDirectory(fileDirectory);
}
}
} sb.Clear();
int lastDotIndex = type.FullName.LastIndexOf('.');
string namespaceName = lastDotIndex > ? type.FullName.Substring(,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[];
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 >= )
propu = propertyString.Substring(,lastIndex);
propu = ConvertType(propu);
if (!usings.Contains(propu) && !string.IsNullOrEmpty(propu)) {
usings.Add(propu);
}
string p = propertyString.Substring(lastIndex+);
string[] ps = p.Split(' ');
ps[] = ConvertType(ps[]) + " ";
p = string.Empty;
for (int i = ; 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[];
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 > ) {
string u = typeString.Substring(,lastIndex);
u = ConvertType(u);
if (!usings.Contains(u) && !string.IsNullOrEmpty(u)) {
usings.Add(u);
}
r = typeString.Substring(lastIndex+);
} else {
r = typeString;
}
r = ConvertType(r);
sb.Append("\t\tpublic " + r + " " + method.Name + "(");
int pcount = method.GetParameters().Length;
int count = ;
foreach (var parameter in method.GetParameters()) {
var paramString = parameter.ParameterType.ToString();
int plast = paramString.LastIndexOf('.');
string ptype = string.Empty;
if (plast > ) {
string pu = paramString.Substring(, plast);
pu = ConvertType(pu);
if (!usings.Contains(pu)) {
usings.Add(pu);
}
ptype = paramString.Substring(plast+);
} else {
ptype = paramString;
}
ptype = ConvertType(ptype);
count ++;
if (pcount == || 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 >= )
typeName = typeName.Substring(,index);
index = typeName.IndexOf('+');
if (index >= )
typeName = typeName.Substring(,index);
index = typeName.IndexOf('<');
if (index >= )
typeName = typeName.Substring(,index);
index = typeName.IndexOf(']');
if (index >= )
typeName = typeName.Substring(, 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);
// }
}
}

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

源代码下载:https://github.com/chinax01/x01.CodeBuilder

x01.CodeBuilder: 生成代码框架的更多相关文章

  1. 【Idea插件】kotlin的orm框架一键生成代码框架

    @font-face { font-family: octicons-link; src: url("data:font/woff;charset=utf-8;base64,d09GRgAB ...

  2. mybatis+maven自动生成代码框架

    说明 通过可配置化,通过数据库自动生成model,da和mapper文件,这对于可定制化开发来说是非常有用的,减少了很多重复的工作. 添加依赖 <properties> <proje ...

  3. 【MyBatis】MyBatis自动生成代码查询之爬坑记

    前言 项目使用SSM框架搭建Web后台服务,前台后使用restful api,后台使用MyBatisGenerator自动生成代码,在前台使用关键字进行查询时,遇到了一些很宝贵的坑,现记录如下.为展示 ...

  4. Android注解使用之通过annotationProcessor注解生成代码实现自己的ButterKnife框架

    前言: Annotation注解在Android的开发中的使用越来越普遍,例如EventBus.ButterKnife.Dagger2等,之前使用注解的时候需要利用反射机制势必影响到运行效率及性能,直 ...

  5. 使用gSOAP工具生成onvif框架代码

    <工具产生背景>          由于SOAP是一种基于xml的文件,手动编写SOAP文件太机械耗时,在这种背景下产生了gSAOP 这个工具,用于生成各种类型的代码,目前支持C/C++, ...

  6. SSM 框架基于ORACLE集成TKMYBATIS 和GENERATOR自动生成代码(Github源码)

    基于前一个博客搭建的SSM框架 https://www.cnblogs.com/jiangyuqin/p/9870641.html 源码:https://github.com/JHeaven/ssm- ...

  7. 使用EA生成多层次的代码框架

    最近工作期间发现了一个非常棒的UML软件[Enterprise Architect UML 建模工具]简称EA,在该软件上绘制框架层面的类之间关系后,可以自动生成相关语言的代码. EA上目前支持的语言 ...

  8. (转)MyBatis框架的学习(七)——MyBatis逆向工程自动生成代码

    http://blog.csdn.net/yerenyuan_pku/article/details/71909325 什么是逆向工程 MyBatis的一个主要的特点就是需要程序员自己编写sql,那么 ...

  9. Onvif开发之代码框架生成篇

    看了前一篇的ONVIF的简单介绍应该对它的基本使用都有了一些基本的了解了吧!下面我讲一步分解向大家介绍下如何通过gsoap生成需要的代码,以及代码中需要注意的问题[基于Linux平台 C开发] 生成O ...

随机推荐

  1. JavaScript语言精粹--执行环境及作用域,this

    1.执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为. 每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中. 虽然我们无法访问,但是解析器在处理数据时 ...

  2. 《JS设计模式笔记》 5,适配器模式

    //适配器模式的作用就像一个转接口. jQuery("#"+id); $id=function (id) { return jQuery("#"+id)[0]; ...

  3. 计算机程序的思维逻辑 (39) - 剖析LinkedList

    上节我们介绍了ArrayList,ArrayList随机访问效率很高,但插入和删除性能比较低,我们提到了同样实现了List接口的LinkedList,它的特点与ArrayList几乎正好相反,本节我们 ...

  4. 读书笔记--SQL必知必会10--分组数据

    10.1 数据分组 使用分组可以将数据分为多个逻辑组,对每个组进行聚集计算. 10.2 创建分组 使用SELECT语句的GROUP BY子句建立分组. GROUP BY子句必须出现在WHERE之后,O ...

  5. 读书笔记--SQL必知必会13--创建高级联结

    13.1 使用表别名 SQL可以对列名.计算字段和表名起别名. 缩短SQL语句 允许在一条SELECT语句中多次使用相同的表. 注意:表别名只在查询执行中使用,不返回到客户端. MariaDB [sq ...

  6. 使用代码向一个普通的类注入Spring的实例

    转载请在页首注明作者与原文地址 一:应用场景 什么是普通的类,就是没有@Controller,@Service,@Repository,@Component等注解修饰的类,同时xml文件中,也没有相应 ...

  7. 代码的坏味道(12)——平行继承体系(Parallel Inheritance Hierarchies)

    坏味道--平行继承体系(Parallel Inheritance Hierarchies) 平行继承体系(Parallel Inheritance Hierarchies) 其实是 霰弹式修改(Sho ...

  8. 【原创】如何确定Kafka的分区数、key和consumer线程数

    在Kafak中国社区的qq群中,这个问题被提及的比例是相当高的,这也是Kafka用户最常碰到的问题之一.本文结合Kafka源码试图对该问题相关的因素进行探讨.希望对大家有所帮助.   怎么确定分区数? ...

  9. LINQ to SQL语句(14)之Null语义和DateTime

    Null语义 说明:下面第一个例子说明查询ReportsToEmployee为null的雇员.第二个例子使用Nullable<T>.HasValue查询雇员,其结果与第一个例子相同.在第三 ...

  10. 浅谈Slick(3)- Slick201:从fp角度了解Slick

    我在上期讨论里已经成功的创建了一个简单的Slick项目,然后又尝试使用了一些最基本的功能.Slick是一个FRM(Functional Relational Mapper),是为fp编程提供的scal ...