• 使用CodeSmith快速规范开发.Net软件


    一、 现状分析 3
    1.1、 纯手工编写代码 3
    1.2、 使用简单的代码生成器(Codematic) 4
    1.3、 使用自己编写的代码生成器 5
    二、 CodeSmith简介 5
    2.1、 软件简介 5
    2.2、 版本说明 7
    三、 CodeSmith原理分析 7
    3.1、Asp3.0运行原理 7
    3.2、CodeSmith运行原理 8
    四、 使用CodeSmith 8
    4.1、简单的属性代码生成 8
    4.2、数据库使用代码生成 10
    4.3、创建公司自己的代码模板 14



    一、 现状分析
    很多程序员在代码开发过程中,都会觉得很多代码都是“重复”的。当然这里所说的“重复”,指的是在代码级别上的重复。也就是说基本的代码架构都是一样的,但参数需要做不同的调整。特别是在数据库开发领域,针对于不同数据表的操作,程序员将需要写很多“重复”的代码。
    公司内部需求定义代码编写规范,比如名称空间、类、变量等的命名。代码结构的调用规范等问题。公司只能通过文档的形式来要求程序员,执行这个规范。但往往在项目开发的过程中(特别是中后期),项目经理是没有时间和精力来保证程序员的代码规范问题的。他们需要把时间和精力更多的放在项目的需求和功能的设计上。
    针对于项目的设计模板,一些程序员往往根据自己的经验,把软件设计的相当复杂。看起来好象,非常体现技术含量,但这对软件的维护和升级是很不好的。可以说软件如果没有维护和升级,那注定是失败的软件项目。
    根据我多年针对于软件项目的开发经验,建议公司对于软件设计过程中保持结构的简单性。这点很重要,这样做将大大提高软件的可维护性。
    1.1、 纯手工编写代码
    当然,这是最原始的开发方法,只要是程序员,都喜欢这种开发方法。因为,在此种机制中,程序员可以不受任何约束,可以充分展示自己的聪明才智。
    但对于公司或者说一个同队来讲,这个机制是很不好的。在公司或团队中,更多的需要规范性和可读性,个人的聪明才智相比之下不是那么的重要。因为在项目的开发方法中,一个问题,可能有N多的解决办法,但在公司或团队中,需要的是更容易理解的解决方案。虽然有可能这种解决方案是相对比较愚蠢的。
    针对于项目经理来讲,不应该把时间和精力放在技术上面,而应该做更好的需求分析和系统设计。这里所讲的系统设计,不是一般意义上的三层或多层架构的设计,而是怎么样更好的实现用户的需求,让用户在软件的使用中,真正觉得软件好用。
    对于PetShop等高级设计思想,我的建议是可以去理解他里面的精髓,但形式上不需要和他们做的一样,因为很多一般程序员是没有办法真正理解的。在项目的过程中,他们需要为此花费很多的时间。再说对于软件的运行效率来讲,我觉得最简单的设计模式,反而是最有效的。
    针对于公司来讲,系统架构设计思路的统一,将有利于项目的维护安全,不会因为项目经理的调离,而没有办法去有效的管理此项目。
    1.2、 使用简单的代码生成器(Codematic)
    简介:
    Codematic 是一款为 C# 数据库程序员设计的自动代码生成器,Codematic 生成的代码基于基于面向对象的思想和三层架构设计,结合了Petshop中经典的思想和设计模式,融入了工厂模式,反射机制等等一些思想。采用 Model + DAL + BLL + Web 的设计,主要实现在 C# 中对应数据库中表的基类代码的自动生成,包括生成属性、添加、修改、删除、查询、存在性、 Model 类构造等基础代码片断,使程序员可以节省大量机械录入的时间和重复劳动,而将精力集中于核心业务逻辑的开发。
    Codematic 同时提供方便的数据库查询管理,SQL脚本生成,存储过程生成,数据库文档生成,Web项目文件发布,代码生成自动导出文件等多项开发工作中常用到的功能,您可以很方便地进行项目开发。

    总论:
    使用Codematic时,确实能够在重复的代码编写上节约不少时间。生成代码时,也可根据需要生成二层或三层架构的代码。
    但生成的代码格式基本一致,程序员不能对模板进行编辑。比如,公司内部需要自己定义一套命名规范或在源代码文件中写入版权信息,此软件就不支持。
    另一方面,通过此软件生成的代码需要使用Codematic自带的类库才能正常运行。此种机制,针对与高端软件客户,是很不理想的。因为,我们不能保证,此类库中的代码是安全的。
    1.3、 使用自己编写的代码生成器
    自己编写代码生成器,也是一种解决方案。针对于每个公司自己的特殊情况,来定义自己的代码生成工具。但此种方法,一方面需要自己开发代码生成工具,工作量比较大,另一方面,对于模板定义,很大部分都需要写死在代码生成工具中。因为通过简单的XML定义,是没有办法真正做到代码生成的灵活性。
    二、 CodeSmith简介
    我在这里需要特别说明的是:CodeSmith只是一个工具,就像VS2003或V2005一样,它的存在只是为了更好的开发和规范代码。系统的业务逻辑还是基于Microsoft .NET Framework SDK来运行的。
    使用它的目的,不光是为了提高软件的开发效率,更重要的是从公司的角度出发来更好的管理每个项目。
    2.1、 软件简介

    CodeSmith是一个基于模板的代码生成器。模板是所生成代码的式样。开发者或构架师可应用CodeSmith来生成任何文本语言的代码。其结果(生成的代码)可通过属性来自定义并包含在众多的标准属性类型之中。另外,用户还可建立自定义的属性类型。
    针对.NET Framework而言,性质可以是任何拥有设计器的.NET对象。例如,它可以是一个简单的分配标题的字符串性质。另一方面,可用TableSchema对象来访问数据库表中的一切内容。
      CodeSmith工具的一个强项是它的语法,其与ASP.NET的方法相当。实际上,你可以在CodeSmith模板中应用C#、VB.NET或Jscript。事实上,CodeSmith可输入任何ASCII语言。
    CodeSmith 包括两个工具,一个是CodeSmithStudio.exe是用来设计和编译模板;另一个是CodeSmith.exe是用来运行模板生成代码的, CodeSmith.exe还可以与VS.NET集成,成为VS.NET的一个外部工具。
    模板编写工具CodeSmithStudio.exe:














    模板使用工具CodeSmith.exe:

    2.2、 版本说明
    目前最新版本是V4.0,此版本加入了工程的概念。针对于模板编写,引入工程概念,将有利于更好的共享模板。
    V4.0中对VS2005的支持将更紧密,很好的支持了VS2005中新的语法规范。
    三、 CodeSmith原理分析
    3.1、Asp3.0运行原理
    说起CodeSmith的运行原理,不得不提一下,asp3.0的运行模式。因为CodeSmith的运行过程和标记语言,很大程度上借鉴了这种思想。不同的是,asp3.0是把代码嵌入到HTML中,使用顺序、判断、循环等基本语法,将HTML根据业务逻辑产生出来,并返回给请求的浏览器。而CodeSmith是将代码嵌入到基本不变的代码中,也是利用顺序、判断、循环等基本命令,将动态的代码和基本不变的代码组合在一起,从而达到动态生成源代码的目的。
    在ASP3.0时,微软使用了解释型的编译器,也就是说当用户请求某个页面时,服务器将动态的解释并生成HTML给浏览器,此种机制被很好的引入到CodeSmith中。
    3.2、CodeSmith运行原理
    CodeSmith实现原理主要可以从以下几点来描述:
    1、支持执行代码块语法;
    通过类似于Asp.Net的语法规范,来定义代码块,将基本不变的部分写死在模板中。模板通过外部定义的属性,来动态的产生需要的代码块。
    模板中可以加入公司的版权信息或者代码作者等基本信息。用于后期对代码进行更好的维护。
    2、支持内联表达式语法;
    在模板定义中,可以使用Asp.Net的语法,来定义表达式。通过顺序、判断、循环等基本程序语法,来根据业务逻辑产生需求的代码。
    3、 支持Code Behind功能;
    Code Behind指的是代码分离技术。即在设计模板时,可以将部分逻辑函数写入到通用的类库中。代码生成时,可以通过INCLUDE命令加载这些函数类库。
    4、 支持属性申明;
    通过配置模板的属性,CodeSmith将根据程序员的业务需求,调入外部参数。.

    四、 使用CodeSmith
    写了这么多,如果大家都我的意见比较支持的话,我们一起来学习CodeSmith的基本功能。否则就当我没作过这次报告。
    4.1、简单的属性代码生成
    首先定义模板的基本信息,包括公司名称、模板名称、作者、模板描述、版本号等。
    <%--
    Company:浙江博海信息服务中心
    Name:测试模板
    Author: jason
    Description: 演示如何通过模板生成C#源程序
    Version:1.0
    --%>
    定义此模板的语言,本试例中使用C#作为模板语言。
    <%@ CodeTemplate Language="C#" TargetLanguage="Text" Src="" Inherits="" Debug="False" Description="Template description here." %>
    定义外部属性变量,用于模板执行时,提供外部变量。
    <%@ Property Name="SampleStringProperty" Type="System.String" Default="SomeValue" Optional="True" Category="Strings" Description="This is a sample string property." %>
    <%@ Property Name="SampleBooleanProperty" Type="System.Boolean" Default="True" Optional="False" Category="Booleans" Description="This is a sample boolean property." %>
    定义引用的.Net类库。
    <%@ Assembly Name="System.Data" %>
    <%@ Import Namespace="System.Data" %>
    模板开始,先定义基本不变的代码部分,将外部变量通过<%=变量%>的形式来引入外部变量,当然也可以通过<%=函数%>的形式来调用外部或本模板中的其它函数。
    My static content here.
    My dynamic content here: "<%= SampleStringProperty %>"
    Call a script method: <%= SampleMethod() %>
    通过外部输入的变量,来决定是否显示部分了符串。
    <% if (SampleBooleanProperty) { %>
    My conditional content here.
    <% } %>
    模板内部定义的函数,则函数是在代码生成模板中执行。产生结果后,则不在C#源文件中显示。内部函数必须使用<script runat="template"></script>来标记。
    函数的写法,将使用普通的C#语法来定义。
    <script runat="template">
    // My methods here.

    public string SampleMethod()
    {
    return "Method output.";
    }
    </script>

    生成结果:
    My static content here.
    My dynamic content here: "SomeValue" //外部设置的属性值。
    Call a script method: Method output. //执行内部函数得到的值。
    My conditional content here. //根据逻辑判断得到的值。
    4.2、数据库使用代码生成
    首先定义模板的基本信息,包括公司名称、模板名称、作者、模板描述、版本号等。
    <%--
    Company:eport
    Name:Demo
    Author: jason
    Description: Demo
    Version:1.0
    --%>
    定义此模板的语言,本试例中使用C#作为模板语言。
    <%@ CodeTemplate Language="C#" TargetLanguage="T-SQL" Description="Create a procedure which have insert function base on a table." %>
    <%@ Assembly Name="SchemaExplorer" %>
    <%@ Import Namespace="SchemaExplorer" %>
    定义需要操作的数据表。
    <%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" Category="DataTable" Description="Table that the stored procedures should be based on." %>
    定义生成源程序包含的作者及描述信息。
    <%@ Property Name="Author" Type="String" Category="Context" Description="The author for this procedure."%>
    <%@ Property Name="Description" Type="String" Category="Context" Description="The description for this procedure."%>
    <script runat="template">
    定义模板内部函数,用于处理每个字段中的特殊逻辑。
    public string GetSqlParameterStatement(ColumnSchema column)
    {
    string param = "@" + column.Name + " " + column.NativeType;
    switch (column.DataType)
    {
    case DbType.Decimal:
    {
    param += "(" + column.Precision + ", " + column.Scale + ")";
    break;
    }
    default:
    {
    if (column.Size > 0)
    {
    param += "(" + column.Size + ")";
    }
    break;
    }
    }
    return param;
    }
    </script>
    定义存储过程模板,使用<%=%>标记,读了外部或内部变量。
    CREATE PROCEDURE dbo.<%=SourceTable.Name %>Insert
    /*
    ==================================================
    Author:<%= Author %>
    CreatedTime:<%= System.DateTime.Now.ToShortDateString() %>
    Description:<%= Description %>
    ==================================================
    */
    循环DEMO表中的所有字段,并调用GetSqlParameterStatement函数,将所有字段根据不同的类型输出。
    <% for (int i = 0; i < SourceTable.Columns.Count; i++) { %>
    <%= GetSqlParameterStatement(SourceTable.Columns[i]) %><% if (i < SourceTable.Columns.Count - 1) { %>,<% } %> <% if (SourceTable.Columns[i].Description != "") { %>--<%= SourceTable.Columns[i].Description %><% } %>
    <% } %>
    AS
    Insert Into [<%= SourceTable.Name %>]
    (
    <% for (int i = 0; i < SourceTable.Columns.Count; i++) { %>
    [<%= SourceTable.Columns[i].Name %>]<% if (i < SourceTable.Columns.Count - 1) { %>,<% } %> <% if (SourceTable.Columns[i].Description != "") { %>--<%= SourceTable.Columns[i].Description %><% } %>
    <% } %>
    )
    Values
    (
    <% for (int i = 0; i < SourceTable.Columns.Count; i++) { %>
    @<%= SourceTable.Columns[i].Name %><% if (i < SourceTable.Columns.Count - 1) { %>,<% } %>
    <% } %>
    )

    生成结果:
    CREATE PROCEDURE dbo.DemoInsert //根据规范,定义存储过程的名称。
    /*
    ==================================================
    Author:jasonhuang
    CreatedTime:2007-3-22
    Description:生成INERT存储过程 //根据规范,定义存储过程的描述信息。
    ==================================================
    */
    //循环定义字段的名称、数据类型、长度等。
    @ID bigint(8), --ID
    @Name varchar(50), --网名
    @RealName varchar(50), --真实姓名
    @Password varchar(50), --登录密码
    @Address varchar(200), --联系电址
    @Postcode varchar(10), --邮编
    @ContactTel varchar(50) --联系电话
    AS
    Insert Into [Demo]
    (
    [ID], --ID
    [Name], --网名
    [RealName], --真实姓名
    [Password], --登录密码
    [Address], --联系电址
    [Postcode], --邮编
    [ContactTel] --联系电话
    )
    Values
    (
    @ID,
    @Name,
    @RealName,
    @Password,
    @Address,
    @Postcode,
    @ContactTel
    )
    4.3、创建公司自己的代码模板
    根据公司自己的特殊情况,我们需要定义公司自己的代码模板。具体规范需要根据实际情况整理出来。
    一般规范包括以下部分:
    (1)、模板的命名规范;
    (2)、模板格式的书写规范;
    (3)、模板文件的版本控制;
    (4)、模板中的变量及函数命名规范;
    (5)、根据业务需求,定义代码规范;
    (6)、引入先进的设计思想,定义易懂、高效的代码规范;
    (7)、引入共享机制,每位程序员都可以根据业务需求,编写自己的模板,并进行共享;
    (8)、公司内部在一段时间内,使用统一的模板规范,不要轻易更换模板规范;
    (9)、模板定义以易懂和可维护性为第一位的,在此基础上,可以加入特殊的编程技巧;
    (10)、公司领导,对每次引入实际应用的代码模板,需要进行评估。
  • 相关阅读:
    关于使用quartz动态增删改定时任务
    关于chrome被篡改主页修复方法
    关于git被误删除的分支还原问题
    mysql数据库备份bat脚本
    同步数据库bat脚本
    读取spring boot项目中resource目录下的文件
    使用Java进行udp-demo编程时碰到的consumer和producter无法连接并报出“java.net.SocketException: Can't assign requested address”问题
    关于在项目中遇到MySQL数据库死锁的问题
    Gitlab仓库搭建及在Linux/windows中的免密使用
    GIT
  • 原文地址:https://www.cnblogs.com/luluping/p/1539185.html
Copyright © 2020-2023  润新知