在这个项目里我负责的部分是读取某子系统从
数据库导出来的两个
XML(不妨假设为A.XML和B.XML)文件并根据文件内容完成本部分的业务工作流程。文件是以共享方式放在
服务器上,我只需要获得一个Session访问即可,因为要求是实时读写文件,所以否定了
下载到本地进行读写的方法,而为了保证程序生命力和数据的完整性,我决定将文件信息一次性读入程序存储空间,并在业务流程中设定当完成某个特定的步骤后回写一遍AB两文件,其中A文件节点可能有增删B文件只是更新某个标志。
一开始设计具体类的时候很容易想到构造和文件结构对应的类,使用庞大的DOM对象?哦,我可不需要那么多累赘。现在我把对应AB两文件的类分别写了个大概出来,很简单如下:
A,B各需要要一个集合类管理,分别命名为clscolA,clscolB,大概如下:
这段代码虽然他够用,又看似天衣无缝,但总觉得不对头,当属性达到一定数量,你有没有发现你将会使用了太多的同样的赋值句?小学语文就告诉过我们适当使用排比句可以为文章造势,但是如果你一口气排比了20条,那就是滥用了,笔者这里A文件每一条记录有三十多个Field,B文件也有十多个,如果这样用下来景象肯定巍巍壮观,先估计一下代码量,A文件每条记录按30个Field,B按15个算,赋值过程便是45行,还不包括格式化处理和排错处理,如果考虑程序扩展性,以后要读更多的文件则必然会伴随更多类似的过程出现,写程序和做人一样,要低调,一定要低调啊,有激情的程序员自然不会如此糟蹋自己的代码,是否能用一个函数或过程解决上述问题呢?新方案应用而生,采用反射(Imports/using System.Reflection),一个通用过程解决所有问题。示例函数如下:
使用这个函数,只需要保证集合类clscolA/B有GenerateAson和Addson两个方法以及clsA/B两子类的属性名称与文件中Field保持一致即可。你只需要传递相应A或者B文件的目标节点名,文件路径,以及对应的集合类即可,此时再看一下赋值过程的代码减少了多少,恩,只有8行,这对于笔者则意味着省去了45-8=37行代码,而且丢弃老套的排比句。
第一阶段战斗算是小试牛刀了一把,如果只算赋值过程代码减少百分数为37/45,接近83%。
一开始设计具体类的时候很容易想到构造和文件结构对应的类,使用庞大的DOM对象?哦,我可不需要那么多累赘。现在我把对应AB两文件的类分别写了个大概出来,很简单如下:
Class clsA/B Property Name1 as string ... End Property Property Name2 as string ... End Property ...... ...... ...... End Class |
A,B各需要要一个集合类管理,分别命名为clscolA,clscolB,大概如下:
Public Class clscolA/B Inherits System.Collections.CollectionBase Public Function GenerateAson() As clsA/clsB 'New并返回一个 clsA or clsB '初始化属性的工作可以在这里进行 End Function Public Sub AddSon(ByVal objSon As clsA/clsB) '增加一条新纪录 InnerList.Add(objSon) End Sub Public Sub Sort() '根据某设定的属性对集合进行排序 InnerList.Sort(New clsSortByName) End Sub '默认Item属性以及更多Method从略 End Class |
好了,现在程序数据的基本框架搭好了,这无疑是十分中庸地解决办法,当然也是十分有效的,本文的主题并不是特别愿意删减这些成熟的代码(当然也仅仅是暂且不动而已)。躯壳已有,剩下的工作就是从文件读取并填充数据,如果你还没有接触过反射或者仅仅限于书本上那点例子,这对你来说可能是一个简单而又枯燥的过程,你于是乎也条件反射似地写起来
New一个clscolA/B(就叫colA/B吧)然后遍历文件或取一个包含所有记录(目标节点)的NodeList,然后作如下状:
With NodeList for i as integer=0 to .Count-1 Dim objson as clsA/B=colA/B.GenerateAson objson.Name1=.item(i).childnodes(x1).innertext objson.Name2=.item(i).childnodes(x2).innertext ...... ...... ...... colA/B.Addson(objson) next i End With |
这段代码虽然他够用,又看似天衣无缝,但总觉得不对头,当属性达到一定数量,你有没有发现你将会使用了太多的同样的赋值句?小学语文就告诉过我们适当使用排比句可以为文章造势,但是如果你一口气排比了20条,那就是滥用了,笔者这里A文件每一条记录有三十多个Field,B文件也有十多个,如果这样用下来景象肯定巍巍壮观,先估计一下代码量,A文件每条记录按30个Field,B按15个算,赋值过程便是45行,还不包括格式化处理和排错处理,如果考虑程序扩展性,以后要读更多的文件则必然会伴随更多类似的过程出现,写程序和做人一样,要低调,一定要低调啊,有激情的程序员自然不会如此糟蹋自己的代码,是否能用一个函数或过程解决上述问题呢?新方案应用而生,采用反射(Imports/using System.Reflection),一个通用过程解决所有问题。示例函数如下:
Public Shared Function FillFromXML(ByVal NodeName As String, ByVal strPath As String, ByVal objFather As Object) As Boolean Try With xmlGetList(NodeName, strPath) For i As Integer = 0 To .Count - 1 Dim st As Object = objFather.GenerateAson Dim ty As Type = st.GetType For Each pp As PropertyInfo In ty.GetProperties With DirectCast(.Item(i), XmlElement) If .SelectSingleNode(pp.Name.ToUpper) IsNot Nothing Then pp.SetValue(st, CType(.SelectSingleNode(pp.Name.ToUpper).InnerText.Trim, String), Nothing) End If End With Next objFather.AddSon(st) Next End With Return True Catch ex As Exception Return False End Try End Function |
使用这个函数,只需要保证集合类clscolA/B有GenerateAson和Addson两个方法以及clsA/B两子类的属性名称与文件中Field保持一致即可。你只需要传递相应A或者B文件的目标节点名,文件路径,以及对应的集合类即可,此时再看一下赋值过程的代码减少了多少,恩,只有8行,这对于笔者则意味着省去了45-8=37行代码,而且丢弃老套的排比句。
第一阶段战斗算是小试牛刀了一把,如果只算赋值过程代码减少百分数为37/45,接近83%。