.Net管锥篇
前言
Hello World
时序问题
SQL, OLEDB.NET
一龙生九子,九子各不同
Composite
XML
Finder
恼人的邮件
IIS
东风不与周郎便,铜雀春深锁二乔
人莫踣于山而踣于石
前言
Yale这两个月学习.NET技术,做了一些程序片段,有些事情明白了,更多的事情并不明白,还有许多是自以为明白其实误解的事情。 Yale在此一一倒出,不敢与文化昆仑比肩,但取“以管窥天,以锥测地”之意。
Hello World
第一件事情就是安装Visual Studio.Net,还是挺容易的,Microsoft的东西就是这个特点,比较容易上手,挺适合我这种初学者的。
安装完之后我启动它,开始做第一个项目,要先选择是新项目还是新的Solution,  之后要指定语言,我以前用过一段时间JAVA, 听说C#和JAVA挺象的,就选了C#。
第一个程序还是多年前的“Hello World!”,只要自己写一行:
Console.WriteLine("Hello World!");
运行一下就出来了。感觉就象已经学会了C#.NET一样,跟专业人士编出来的一样简洁优美。
后来知道了,光有这一行是不行的, C#根本不认识Console, 所以在最前面要加上: using System;
表示Console这个类在System这个包中。
这点跟JAVA有一点不太一样, JAVA中java.lang这个包是不需要import进来的,JAVA会自动地把它import进来。
C#中程序的运行入口是Main(),原型是:
public static void Main(string[] args)
这一处是我非常喜欢的,跟JAVA几乎一样,差别在于函数(方法)的首字母拼写的约定不同。
也许长期用JAVA的原因,我总觉得写这么一个小小的程序还要费劲用复杂的VS.NET的花花界面挺不是事的,就想命令行的简单方式,比如JAVA中的javac和java命令。既然.NET也是虚机运行的,也应当有这样的命令吧。
还真有,我在c:\winnt\microsoft\framework\v1.0.3705
目录下到了csc命令,它就是C#程序的编译程序。我用它编译完Hello.cs之后,发现生成的竟然是,让人十分惊诧,我以前设想的是Hello.class之类的。
接着我开始怀疑以前的说法是不是对的:“.NET是跨平台的”,既然生成了exe,怎么跨平台的呢?再往下我运行这个程序,居然好使。我又将拷贝到一个普通的机器上,就是说机器上没有安装.NET framework,结果是根本不能运行,这时候我明白了,原来此exe不是传统的Win32 exe, Windows一看到是这种格式的exe, 就会自动启用.NET虚拟机去执行它。这就是它不象Java运行程序时需要显示执行虚拟机的原因。但是这样,也使.NET虚拟机不能和Windows明白分离,这又是Microsoft有意为之吧。
在做了几个小程序之后,我想把它们编到一起,就在VS.NET中New了一个项目叫做
foo,将它们引进来,每个程序中添上一行:
namespace Yale
这一方面挺象JAVA的package的。
编译完毕之后生成了foo.dll, 凭想象我觉得这也不是传统的Win32 dll.
再在别的程序中引用foo.dll中的方法时,需写上诸如Yale.Dummy.PutAbc()才能有效,或者在开头写上import Yale; 正如需用到Console类就得写上import System;一样。
.NET的namespace和JAVA的package不太一样, JAVA强烈倚赖于文件系统,namespace和文件目录是同构的,而.NET的namespace是一个概念结构,不和文件目录对应。比较而言,我个人更加接受.NET的做法。这样,一是自由,二是安装很方便。
时序问题
讲了一大通了,尽是初级废话,现在得讨论一下我用.Net做的几个具体事情了。
我试的例子是数据库方面的管理程序,平庸的很,不过目前我认识的大部分程序员
都是写这一类程序,应当说还是有它的广泛代表性的。我不能说我的是好的,只
是讲述一下遇到这类那类问题时我是怎么考虑的,我相信大家都会遇到同样的问题。
基本上,我将数据库方面的管理程序分成三大功能块:基础设置(Setup),交易(Transaction),查询报表(Inquiry&Report)。
Setup模块基本上与基础资料表相关,能够做Select, Insert, Delete, Update
就行了。所以我决定用一个类来对应一个表,比如对division表,我就用Division 类对应。我立刻就碰到一个问题, Division表示的是“某一个Division”,
那么用什么表示division的集合呢?一个方法是用一个叫做Divisions的类表示
“一组division”, Divisions成为一个真正包含数据的容器;另一种方法是用
一个DivisionHome的类作为操作division的入口, DivisionHome本身并不包含
数据,这有一点象EJB的Home-Entity模型。
这两种方法有很大的不同,不仅仅在于“容器”和“入口”的差别,更大的差别在于
时序,我把它们分别叫做S-Mode和Home-Mode。
我们都知道计算机是一个Bool逻辑系统,同时也是一个时序逻辑系统,对任何一种
设计方案,我们都要了解各部件之间的随时间的动态变化关系,可以用“时序图”(Sequence Diagram)来表示。
我们先看S-Mode的时序:
Create a new division:
对这个Use Case, 我们可以先new Divisions(), 再调用一个Divisions类中的方法,如division = divisions.CreateDivision();  在CreateDivision方法中new
Division(), 并将新生成的division加入容器中. 这时候引出一个问题,什么时候进行数据库操作?需要在new Division()的时候同时进行数据库操作吗?从new Division的语义学角度,好象应当是在此时进行数据库操作,但从实际操作来看,很多种情况下,现在根本不可能进行数据库的操作。好,我们就不把数据库操作放到new Division里,那么Divisions这个类中就得提供一个更新数据库的方法,比如Divisions.Update(); 这个方法将用目前容器中的所有division对象与数据库进行比较,如果不存在就insert, 存在就update。
User          Divisions                  Division                  Database
从上图可以看出,这种设计中, create一个division时其实还没有database什么事。我们仅仅是在内存里凭空构造了一系列的division, 将它们放到container中。
我也考虑过用两个CreateDivision方法,一个是CreateDivision(); 另一个是CreateDivision(string sDivID), 在这个CreateDivision方法中,可以调用Division类的新的构造函数Division(string sDivID), 从而与database关联。我又有一点担心接口的复杂,总希望能给用户一个统一的简单的接口。
那么,在这种设计方案下,更新数据库的Sequence Diagram如下:
Update Division diagram A:
或者是update division diagram B:
交易时间字符串是什么A与B的差别在于谁来操纵database, 方案A的情况下, Division其实只是一个与table对应的虚的内存结构了,而B方案中Divisions不直接操作database, 只保持内存的container定位,但是非常不幸的是留下了一个麻烦, Delete操作怎么处理?我们看到,由Division与Database
同步,只是单向的,对于container中删除的division, 数据库中无法删除!办法是有的,即单独处理Divisions中的delete.
Remove division
User          Divisions                  Division                  Database
B引过来的问题,所以让Division进行数据库操作。
还需要讨论的就是集合的问题,先看Sequence Diagram:
User          Divisions                  Division                  Database
而Division又变成了一个内存中虚的结构。
好了,这就是S-Mode下的时序图了。
Home-Mode下也相应的有自己的时序图:
Use case A. Create a new division
Use Case B. get a existed division and update it
User          DivisionHome            Division                  Database
Use Case C. Delete a division    User          DivisionHome            Division                  Database
Use Case D .  Get a set of divisions                                                                                                                      User          DivisionHome            Division                  Database
User          DivisionHome            Division                  Database
由于Home-Mode 中不把DivisionHome 看成是一个容器, 只是看成是一个接口,所以它没有一片缓存区域, 每一个对象的操作最后都要落实到database 才行。而S-Mode 中Divisions 可以看成是一个内存数据表, 操作都是缓存在container 中, 最后更新database 。
上面的Sequence Diagram 并没有一定之规, 主要是考虑对外接口的统一简洁, 还有就是确定在哪里操作数据库。我只是给出了一种可能性。
我总是希望能够对手头的设计有一种简单优美的表达, 结果并不能令人满意。
最后我选择了以Home-Mode 为主的混合模式, 原因可能是我个人比较偏好JA VA 。是对还是错, 只能由时间评说。
SQL, OLEDB.NET
当确定了时序之后, 我现在要考虑database 操作了。
这些年, 我经常在有效性和通用性的选择之间摇摆。 我以前在一家专做数据库程序的公司干过三年, 支持过许多数据库, 如MS SQLServer, Sybase, Oracle, DB2, Informix, Access, SQL Anywhere 等等, 当时的技术总监偏向于有效性, 所以大量使用了数据库专用的SQL , Trigger , user-defined function 和Stored Procedure , 在程序的与DBMS 相关的地方都用CASE 语句分开, 效果是不错的。同时我也
知道了有些著名的软件, 他们的设计中只使用基本的

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。