没头没尾--项目开发笔记:如何开发代码更新工具?!(下)

来源:互联网 发布:淘宝直通车烧钱 编辑:程序博客网 时间:2024/05/22 17:03
 

(接上篇http://www.csdn.net/develop/article/16/16299.shtm

Ø         代码更新的替换过程

代码的更新的过程主要是搜索对应的文件的目录,将所有的目标文件找出,将目标文件读入字符串,根据模板文件内容对目标文件进行处理。下面是个简单说明:

1.读入输入模板文件,读出TemplateTag,读出各个CodeSession存入对应的数据结构中;

2.扫描输入的原始文件目录,进行扫描,将符合替换条件的文件找出,调用代码更新的模板;

3.将文件读入内存,查找其中有没有TemplateTag的内容,如果没有查找结果为False,则调用第4步,如果查找结果为True,直接调用第5步;

4.读出各个CodeSessionnewsource节中的内容,调用方法修改文件的字符串内容。

然后直接调用第7步;

5.将文件字符串的TemplateTag内容用空字符串替换;

6.读出各个CodeSessionoldsource节中的内容与newsource节中的内容,使用String.Replace的方法将oldsource内容换成newsource内容;

7.将文件字符串加入TemplateTag内容之后重新写回文件之中。

下面是表示此步骤的部分代码:

              //GerentorCode函数,代码生成与更新的调用入口

                  public void GerentorCode()

                  {

                            //本函数之前已经将模板文件读入this.TemplateStructure之中,

                            //其中this.TemplateStructure是一个Dataset类型

                           //**********************************//           

                           //m_szTagString存入TemplateTag中的内容

m_szTagString = this.TemplateStructure.Tables["CodeTemplate"].Rows[0]["TemplateTag"].ToString();

                            //遍历CodeSession

                           foreach(DataRow row in this.TemplateStructure.Tables["CodeSession"].Rows)

                            {

                                     //分别将对应不用的CodeSession节中的内容取出

                                     //放入不同的函数属性字符串中

                                     if(row["value"].ToString() == "Try")

                                     {

                                              //Try部分要值入的代码

                                              m_szTryString = row["newsource"].ToString();

                                              //Try部分以前值入的旧代码

                                              m_szOldTryString = row["oldsource"].ToString();

                                     }

                                     if(row["value"].ToString() == "Catch")

                                     {

                                              //Catch部分要值入的代码

                                              m_szCatchString = row["newsource"].ToString();

                                              //Catch部分以前值入的旧代码

                                              oldcatchstring = row["oldsource"].ToString();

                                     }

 

                            }

                           

                           //GerentorCode传入路函数径值的函数,

                            //将会对本路径下所有的Web Service文件进行代码生成或代码更新的处理

                           GerentorCode(m_szWebServicePath);

                  }

                 

                  //GerentorCode函数,代码生成与更新的调用入口

                  public void GerentorCode(String szPath)

                  {

                            //存储文件内容的字符串

                           string szSourceCode;

                            //生成目标文件目录的结构

                           string[] directoryEntries = System.IO.Directory.GetFileSystemEntries(szPath);

                            //临时字符串

                           string szTemp;

                           string szszTemp1;

                           int nStart;

                           StreamWriter  streamWriter;

                           StreamReader  streamReader;

                           FileStream sb;

                           String szReturnType;

                            //遍历目标文件目录      

                           foreach (String path in directoryEntries)

                            {

                                     //如果还是目录,则循环调用本函数

                                     if(!Directory.Exists(path))

                                     {

                                               //判断是否web service的代码文件

                                              if(path.Substring(path.Length - 8,8) == ".asmx.cs")

                                               {

                                                        //将代码文件读入szSourceCode

streamReader = new StreamReader(path, System.Text.Encoding.GetEncoding("GB2312"));

         szSourceCode = streamReader.ReadToEnd();

         streamReader.Close();

         //判断是否包含m_szTagString;即判断是否已经被植入过代码

         if(szSourceCode.IndexOf(m_szTagString) != -1)

         {

                  //如果已经被植入过代码。则替换TemplateTag

                  //替换Try;替换Catch

                  szSourceCode = szSourceCode.Replace(m_szTagString, string.Empty);

                  szSourceCode = szSourceCode.Replace(m_szOldTryString, m_szTryString);

                  szSourceCode = szSourceCode.Replace(m_szOldCatchString, m_szCatchString);

         }

         else

         {

         //循环查找WebServic中的方法;(已知道规则是所有WebService方法以"[WebMethod("开头)

                  int nWebMethod = szSourceCode.IndexOf("[WebMethod(");

                  int nWebMethodEnd = -1;

                  while (nWebMethod != -1)

                  {

                            //调用方法得出对[WebMethod(下面第一个"{"对应的"}"的位置

                           nWebMethodEnd = GetWebMethodEnd(nWebMethod, szSourceCode);      

                            //也就是将整个的Web Service的方法字符串取出存入szTemp

                  szTemp = szSourceCode.Substring(nWebMethod, nWebMethodEnd - nWebMethod + 1);

                            //备份szTemp,为下面的替换进行准备

                           szTemp1 = szTemp;

                           nStart = szTemp1.IndexOf("{");

                            //第一个"{"号之后加入try的字符串

                           szTemp1 = szTemp1.Insert(nStart + 1, m_szTryString);

                            //与第一个"{"对应的"}"之前加入catch的字符串

                           szTemp1 = szTemp1.Insert(szTemp1.Length -1 , m_szCatchString);

                            //将备份的szTemp进行替换

                           szSourceCode = szSourceCode.Replace(szTemp,szTemp1);

                           nWebMethod = szSourceCode.IndexOf("[WebMethod(", nWebMethod + 1);

                  }

         }                           

         //将文件重新写入                   

         sb = new FileStream(path, FileMode.Create);

         streamWriter = new StreamWriter (sb, System.Text.Encoding.GetEncoding("GB2312"));

         //在文件字符串的开头加入TemplateTag,即打上标识,为下一次更新做准备

         streamWriter.Write(m_szTagString + szSourceCode);

         streamWriter.Close();

}

         }

         else

         {        

                  //如果是目录,递归调用本函数

                  GerentorCode(path);

         }

                            }

                  }

Ø         代码更新的输出

代码更新的输出没有什么特殊的,只是使用新的文件内容字符串生成一个文件将以前的文件进行覆盖。

 

 

l         需要注意的部分

更新C#可以使用的代码出现的了一些问题。这里写出来,以免以后的朋友也走同样的弯路。这些问题的出现主要是与IDE环境有关系。Visual Studio.net的环境会自己对加入的代码进行一些自动的处理,这些处理将会导致最后代码更新不成功。下面是遇见的问题与解决方案:

Ø         IDE的问题:

8.问题描述

生成的代码在从IDE打开之后,或者是重新进行编译之后。代码更新工具对代码文件的更新失效。

9.出现原因分析

IDE自动对代码进行了格式的整理。被替换的代码的格式已经被修改。

例如,以下的代码被注入函数之内:

<TAB><TAB>//**以下的代码为生成的代码,请不要进行修改**//

其中<TAB>是不可见的,只是表示为代码不同行之间的对齐的关系。

但此文件被IDE打开或或被编译之后,代码可能会被IDE修改,形成以下情况:

<TAB><TAB><TAB>//**以下的代码为生成的代码,请不要进行修改**//

由于我们的机制是要求找出可以与Old Source 中内容完全等同的部分以进行代码的更新,所以一定会更新失败。

²        解决方案

解决方案可以有很多种,这里我只提供出我的一种方案。我的解决方案很简单,将IDE中已经被修改的部分拷贝出来,放入Old Source 节中。这样的话,替换时就不会出现失败的情况。

例如,在上例中,我将带三个<TAB>的代码从IDE中拷贝出来,替换模板文件中的Old Source节。从而在代码更新的过程中,代码的更新就可以成功。

当然还可以有别的方法,比如可以将<TAB>忽略以进行代码更新;或者直接找出一个方法用已经生成代码文件来更新与同步模板文件。或者在模板文件中定义出两个或两个以上的oldsource节对应一个newsource节,等等。方法有很多,这里就不一一说明了。

这里要重新来强调代码生成工具与代码更新工具制作的目的了。制作代码生成工具或代码更新工具的目的实际上非常的单纯:通过各种的手段来提高开发过程的工作效率。最粗糙的代码生成工具只可以帮助提高一点点开发效率,较为细致与全面的代码生成工具可能可以从很深的层次上提升开发过程的效率。但是,这些暂时都只是工具。没有与整个的开发人员,开发工具,以及我们所开发的项目进行更深程度的结合,从而形成出一整套完整的开发流程,才有可能真正的去提升开发工作的生产率。

 

下周又应该到写项目总结的时候,这一个阶段遇见的问题比以前加起来遇见的问题还要多,很多朋友们以前警告过我的问题都出现了,我想具体的说一些,并对出现的问题进行一些分析。