根据 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. 使用python crontab设置linux定时任务

    熟悉linux的朋友应该知道在linux中可以使用crontab设置定时任务.可以通过命令crontab -e编写任务.当然也可以直接写配置文件设置任务. 但是有时候希望通过脚本自动设置,比如我们应用 ...

  2. 【原】SDWebImage源码阅读(四)

    [原]SDWebImage源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 SDWebImage中主要实现了NSURLConnectionDataDelega ...

  3. OpenCASCADE Data Exchange - 3D PDF

    OpenCASCADE Data Exchange - 3D PDF eryar@163.com Abstract. Today most 3D engineering model data are ...

  4. iOS 支持 IPv6

    苹果的规定:2016年6月1日提交到App Store必须支持IPv6-only网络. 官方文档:https://developer.apple.com/library/mac/documentati ...

  5. Android动画效果之Tween Animation(补间动画)

    前言: 最近公司项目下个版本迭代里面设计了很多动画效果,在以往的项目中开发中也会经常用到动画,所以在公司下个版本迭代开始之前,抽空总结一下Android动画.今天主要总结Tween Animation ...

  6. 后台管理UI的选择

    最近要做一个企业的OA系统,以前一直使用EasyUI,一切都好,但感觉有点土了,想换成现在流行的Bootstrap为基础的后台UI风格,想满足的条件应该达到如下几个: 1.美观.大方.简洁 2.兼容I ...

  7. 原生JS实现"旋转木马"效果的图片轮播插件

    一.写在最前面 最近都忙一些杂七杂八的事情,复习软考.研读经典...好像都好久没写过博客了... 我自己写过三个图片轮播,一个是简单的原生JS实现的,没有什么动画效果的,一个是结合JQuery实现的, ...

  8. 国内maven镜像,快的飞起

    在oschina关来关去的烦恼下,终于受不了去寻找其他公共库了. 阿里云maven镜像 <mirrors> <mirror> <id>alimaven</id ...

  9. TypeScript 强类型 JavaScript – Rafy Web 框架选型

    今天看到了 AngularJs 2.0 版本将基于 TypeScript 构建 的消息.与同事们对 TypeScript 展开了讨论.本文记录一些个人的想法. 理想的 JavaScript 开发模式 ...

  10. 03 通过Button打开另一个的frm

    private void Form1_FormClosing(object sender, FormClosingEventArgs e) { DialogResult re = MessageBox ...