根据 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. HTML5_07之WebSocket

    1.HTML5新特性之WebSocket: ①HTTP协议的不足:基于“请求——响应”模型,只有在客户端发送请求后,服务器才会给予响应:对于实时的股票走势图,以及聊天通讯等无法满足需求: ②解决方案: ...

  2. Java总结篇系列:Java泛型

    一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下面这段简短的代码: 1 public class GenericTest { 2 3 public static void main(Stri ...

  3. EXISTS 引入子查询时,在选择列表中只能指定一个表达式

  4. 【.net 深呼吸】自定义缓存配置(非Web项目)

    在前一篇烂文中,老周简单讲述了非Web应用的缓存技术的基本用法.其实嘛,使用系统默认方案已经满足我们的需求了,不过,如果你真想自己来配置缓存,也是可以的. 缓存的自定义配置可以有两种方案,一种是用代码 ...

  5. dom addeventlistener与id 绑定事件的区别

    文档中有写. //addEventListener() 方法用于向指定元素添加事件句柄. //提示: 使用 removeEventListener() 方法来移除 addEventListener() ...

  6. 细说Promise

    一.前言 JavaScript是单线程的,固,一次只能执行一个任务,当有一个任务耗时很长时,后面的任务就必须等待.那么,有什么办法,可以解决这类问题呢?(抛开WebWorker不谈),那就是让代码异步 ...

  7. Android GPS应用开发

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5715879.html GPS定位系统由三部分组成,即由GPS卫星组成的空间部分,若干地面组成的控制部分和普通 ...

  8. Java Map hashCode深究

    [Java心得总结七]Java容器下——Map 在自己总结的这篇文章中有提到hashCode,但是没有细究,今天细究整理一下hashCode相关问题 1.hashCode与equals 首先我们都知道 ...

  9. Entity Framework 教程——创建实体数据模型

    创建实体数据模型: 本文将带你创建实体数据模型(EDM)SchoolDB数据库和理解基础建设模块. 实体数据模型(EDM)是用于描述实体之间关系的一种模型,以下将使用Visual Studio 201 ...

  10. C#连接Access与SQL Server

    1.连接Access数据库 string strConnection = "Provider=Microsoft.Ace.OleDb.12.0; Data Source=" + S ...