根据 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. Qt5 开发 iOS 应用之访问 SQLite 数据库

    开发环境: macOS 10.12.1 Xcode 8.1 Qt 5.8 iPhone 6S+iOS 10.1.1   源代码: 我在 Qt 程序里指定了数据库的名称来创建数据库,在 Win10.An ...

  2. jQuery UI与jQuery easyUI的冲突解决办法

    jQuery UI与jQuery easyUI都是基于jQuery开发的.难免里面会有些方法名冲突! 因此对jQuery.easyui其中的两个方法名:resizable 和 draggable进行替 ...

  3. ITTC数据挖掘平台介绍(四) 框架改进和新功能

    本数据挖掘框架在这几个月的时间内,有了进一步的功能增强 一. 超大网络的画布显示虚拟化     如前几节所述,框架采用了三级层次实现,分别是数据,抽象Node和绘图的DataPoint,结构如下:   ...

  4. C++服务器开发之基于对象的编程风格

    Thread.h #ifndef _THREAD_H_ #define _THREAD_H_ #include <pthread.h> #include <boost/functio ...

  5. 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 工作原理和相关组件(三)

    RAC 工作原理和相关组件(三) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...

  6. mailto实现将用户在网页中输入的内容传递到本地邮件客户端

    背景: 想在自己的网站中有这样一个设计: 用户点击提交按钮之后,就会打开本地邮件客户端,并自动将他在输入框中输入的内容作为邮件的内容,像下面这样: mailto可以帮助实现这个功能. 简介: mail ...

  7. 大话keepalive

    大话keepalive 我们说到keepalive的时候,需要先明确一点,这个keepalive说的是tcp的还是http的. tcp的keepalive是侧重在保持客户端和服务端的连接,一方会不定期 ...

  8. 学习EF之贪婪加载和延迟加载(1)

    从暑假开始接触code first以来,一直感觉很好用,主要在于开发过程中以业务为中心可以随时修改数据模型生成数据库,还有一个原因就是查询起来很方便 这里找了一个以前database first的一段 ...

  9. [连载]《C#通讯(串口和网络)框架的设计与实现》- 10.宿主程序详细设计

    目       录 第十章           宿主程序详细设计... 2 10.1        配置文件设计... 3 10.2        加载设备驱动... 4 10.3        加载 ...

  10. JS高程4.变量,作用域和内存问题(3)垃圾收集

    JavaScript的自动垃圾收集机制 执行环境会负责管理代码执行过程中使用的内存,编写JavaScript程序时,所需内存的分配以及无用内存的回收完全实现自动管理. 原理: 找出那些不再继续使用的变 ...