RSS 2.0 Feed
我写的文章
摘要: 获取 Mono 目前可以通过以下四种途径获取 Mono 软件包 。 •? 到 Mono 的官方网站下载发行版安装包: 这里提供了各种不同种类的正式发行版或阶段性发行版,人们可以自由选择所需要的类型。这里所提供的安装包一般都经过了测试,能正确的编译和运行。 下载地址在: http://www.go-mono.com/download.html •? 日发行包: 假如你希望能密切的跟踪 Mono 的开发进展,或者你想看到 Mono 的开发历史脚步,你可以在 http://go-mono.com/daily/ 这个地址获取 Mono 的日发行包。日发行包包括了每一天 Mono 项目的开发进展。共分为以下 3 种不同的类型: Mono: 这是一个可以进行编译的运行时和类库的源代码包(包含了 C# 的所有二进制控件)。 只要你有一个 C 编译器就可以编译和安装使用了。最新的版本可以直接通过 http://go-mono.com/daily/mono-latest.tar.gz 来下载。 MonoCharge: 包含了所有进行编译过的 Mono 的 C# 组件和可执行程序。可以使用它来全面更新你已安装的 Mono 类库和工具。 最新版本可以直接通过 http://go-mono.com/daily/monocharge-latest.tar.gz 来下载。 MonoLite: MonoLite 包和 MonoCharge 包一样,也提供了让你更新 Mono 的能力,不过它只包含了最基本的核心类库 corlib, System, System.Xml 和 C# 编译器。 最新版本可以直接通过 http://go-mono.com/daily/monolite-latest.tar.gz 来下载。 •? 通过 CVS 服务器获取 Mono 源码 . CVS 是一个功能强大的源代码管理服务器。假如你认为每天更新一次的日发行包还是不能满足你狂热的追求最新代码的需求的话,那么还可以通过访问 Mono 的 CVS 服务器直接获取 Mono 正在开发中的源代码库,因为有可能你得到的代码是一分钟前由 Mono 的开发人员刚刚提交上去的。 在 Linux 下访问: 首先要确认你的系统上已经安装了 CVS 客户端软件,如果没有的话,可以到 http://www.cvshome.org/ 去下载。 在控制台下输入如下命令: export CVSROOT=server:anonymous@anoncvs.go-mono.com:/mono cvs login (系统提示要输入密码,可以直接回车) cvs -z3 co mono 其中的......[阅读全文]

posted @ | Feedback (3) |

摘要: 专栏作品 如何在.NET中访问MySQL数据库卢彦 引言 如果你不是只在大集团公司工作过的话,你一定会有机会接触到MySQL,虽然它并不支持事务处理,存储过程,但是它提供的功能一定能满足你的大部分需求,另外,简洁的MySQL也有一些它独到的优势,在有些时候,它的速度甚至超过大型数据库。 那么如何在.NET中访问MySQL数据库呢?也许很多人马上会说:用OLEDB嘛,但是事实上采用.NET OleDb Data Provider并不能访问MySQL,如果你使用的话,系统会提示你:"Net Data OLE DB 提供程序 (System.Data.Odbc) 不支持 MSDASQL 提供程序(用于 Odbc 驱动程序的 Microsoft OLE DB 提供程序)。",是什么原因我并不知道,按照MySQLDriverCS的作者的说法就是它被"abandoned by the owner",呵呵,兴许还有些故事。 幸好,我们还有其它的选择,这里就要介绍两种访问MySQL数据库的办法。 使用ODBC.NET ODBC.NET(全称ODBC .NET Data Provider)是一个免费的.NET Framework附加组件,需要到微软公司的网站上去下载,下载地址为:http://download.microsoft.com/download/dasdk/Install/1.0.4030.0/W98NT42KMeXP/EN-US/odbc_net.msi,它需要系统已经安装MDAC 2.7或者更高版本。另外,还需要安装MySQL的ODBC驱动程序,下载地址为:http://www.mysql.com/downloads/api-myodbc-2.50.html,还需要在"ODBC数据源管理器"中配置一下DSN,如下图所示: 在对象的设计上,ODBC.NET也跟OLEDB,SQL等一样,分别为OdbcConnection, OdbcCommand, OdbcDataAdapter, OdbcDataReader,用法也完全一样,如果你希望用ODBC .NET来代替以前的OleDb .NET Data Provider,事实上完全可以通过查找替换的办法来修改你的程序。 以下是一段代码示例: try { string constr = "DSN=MySQL;" + "UID=;" +"PWD="; ; conn = new OdbcConnection(constr); conn.Open(); string query = "insert into test.dbtable values10,'disksidkfsdi', 'asdfaf', 'adsfasdf')"; string tmp = null; OdbcCommand cmd = new OdbcCommand(query, conn); for(int i = 0; i < 100000; i++) { cmd.ExecuteNonQuery(); } cmd.Dispose(); conn.Close(); query = "select * from test.dbtable"; OdbcCommand cmd2 = newOdbcCommand(query, conn); conn.Open(); OdbcDataReader reader = cmd2.ExecuteReader(); while(reader.Read()) { tmp = reader[0].ToString(); tmp = reader[1].ToString(); tmp = reader[2].ToString(); tmp = reader[3].ToString(); } conn.Close(); query = "delete from test.dbtable"; OdbcCommand cmd3 = newOdbcCommand(query, conn); conn.Open(); cmd3.ExecuteNonQuery(); } catch(Exception ex) { MessageBox.Show(ex.Message); } finally { conn.Close(); } 只要是用C#写过数据库应用的人一定能知道,上面的代码执行了十万次插入数据和读取数据,最后将数据记录全部删除的操作。 使用MySQLDriverCS 可能大部分的人都不知道这个东西,MySQLDriverCS是MySQL数据库的一个免费开源的.NET驱动程序。和Sql .NET Data Provider是为Sql......[阅读全文]

posted @ | Feedback (1) |

摘要:用Visual C#编写仿MSN Messager的滚动提示窗口卢彦 引言 大家一定都用过MSN Messager了吧?每当有新邮件或者是新消息到来的时候,MSN Messager便会从右下角升起一个小窗口提醒您,然后又降下去。当你在聚精会神的在电脑上做一件事的时候,一定不会喜欢突然被"咚"一下出现在屏幕中心的对话框打扰,它的这种设计不但非常体贴用户,而且效果还很酷。如果您写了一个程序驻留在后台并要求在需要的时候会提醒用户,并且希望也能实现这种效果,那么请跟我一步一步来做下图所示的这个仿MSN Messager的滚动提示窗口。 实现方法 效果示例图 第一步,建立一个Windows Application,然后在主form中放置一个Button,如下图所示: 第二步,给这个Application添加一个窗体(Form2),把窗体的FormBorderStyle属性设置为None(无边框模式),然后把TopMost属性(总在最上方)属性设置为True,把ShowInTaskbar属性(是否在 Windows 任务栏中显示窗体)设置为False,并在窗体上加上你打算要显示的文字(实际应用中一般是在程序中动态加载),将窗体的背景设置为你想要的图片和合适的大小。最后再放上三个Timer控件,其中,timer1控制窗体滚出的动画,timer2控制窗体停留时间,timer3控制窗体的滚入动画,将它们的Interval属性设置为10。参见下图 第四步,编写代码,在Form2中添加两个属性用来设置窗体的显示大小: private int heightMax, widthMax; public int HeightMax { set { heightMax = value; } get { return heightMax; } } public int WidthMax { set { widthMax = value; } get { return widthMax; } } 添加一个ScrollShow的公共方法: public void ScrollShow() { this.Width = widthMax; this.Height = 0; this.Show(); this.timer1.Enabled = true; } 添加一个StayTime属性设置窗体停留时间(默认为5秒): public int StayTime = 5000; 添加ScrollUp和ScrollDown方法来编写窗体如何滚出和滚入: private void ScrollUp() { if(Height < heightMax) { this.Height += 3; this.Location = new Point(this.Location.X, this.Location.Y - 3); } else { this.timer1.Enabled = false; this.timer2.Enabled = true; } } private void ScrollDown() { if(Height > 3) { this.Height -= 3; this.Location = new Point(this.Location.X, this.Location.Y + 3); } else { this.timer3.Enabled = false; this.Close(); } } 在三个Timer的Tick方法中分别写入: private void timer1_Tick(object sender, System.EventArgs e) { ScrollUp(); } private void timer2_Tick(object sender, System.EventArgs e) { timer2.Enabled = false; timer3.Enabled = true; } private void timer3_Tick(object sender, System.EventArgs e) { ScrollDown(); } 在Form2的Load事件中初始化窗体变量: private void Form2_Load(object sender, System.EventArgs e) { Screen[] screens = Screen.AllScreens; Screen screen = screens[0];//获取屏幕变量 this.Location = new Point(screen.WorkingArea.Width - widthMax......[阅读全文]

posted @ | Feedback (6) |

摘要: 专栏作品 利用XML实现通用WEB报表打印卢彦 方案适用性. 1. 远程数据打印。需要打印的数据并不在本地,必须进行远程读取。 2. 需要精确控制打印效果,包括页面格式,分页,附加条目,表格等。 3. 出于安全性考虑,不能直接连接到数据库。 方案原理 其实原理很简单,通过XML强大的自定义功能,我们便能方便的自定义出我们所有需要的格式控制标签,在服务器端进行动态编码后通过WEB服务器传到客户端,然后在客户端进行格式解析,根据服务器端定义的打印格式从客户端直接控制打印机打印出我们需要的报表。 技术选择 由于报表打印比较复杂,为了能够精确控制打印格式,不能采用WEB浏览器页面打印的方式进行报表打印工作,只能采取自编程控制客户端的打印工作。由于.NET framework的winform可以直接嵌入到网页中,我们在这里选用了该技术,但是请注意,我这么做并不代表.NET winform是唯一的选择,其实您可以采用任何客户端代替它,例如Java Applet或者ActiveX,甚至是一个普通的应用程序都能行。 不允许直接连接到数据库,因此只能采用XML文件进行中间数据交换格式,通过普通WEB服务器的默认80端口进行数据传输。事实上,我简直找不到其它更理想的方案了,当然,web service也许能算是一种,但是它采用的是SOAP传输数据,从原理上看,应该和我们采用的XML属于同种类技术。 再补充说明一下我为什么要采用.NET编写的受控组件,优点在于: 1. 它不需要进行客户端注册。相对于ActiveX的一个大优点。 2. 比ActiveX安全性高。在.NET Common Language Runtime的控制之下运行 3. 编写方便。我喜欢C#和Visual Studio .NET。 4. 有很强大的打印控制功能。利用.NET framework类库。 5. 直接支持XML技术。 6. 和IE兼容性高。同为Microsoft公司产品。 另外,需要注意一点就是,在.NET framework sp1和sp2中默认的安全级别是不能直接运行受控组件的,但是在.NET framework 1.1 beta中又改了回来,可以直接运行了。 服务器端您则可以采用现有的服务器系统和数据库,不需要新添加任何新硬件设备和新的.NET服务器管理人员,他们往往是些要求拿高薪的家伙。 :) 服务器的工作流程为: 1. 接受客户端的标准XML模版查询。 2. 需要根据查询要求将数据库数据格式转换成标准的XML数据格式。 3. 将XML数据通过80端口发送出去。 可行性分析 由于现在的大部分数据库都支持XML格式的数据查询和转换,如SQL Server 2000,Oracle 9i,IBM DB2等大型关系型数据库。只需要通过简单的设置就能直接进行XML数据转换工作。如果数据库不能支持直接XML数据转换,也可以籍由一些服务器端脚本程序进行脚本转换工作,比如JSP,ASP,PHP等等。 客户端也不需要任何特殊的设置工作,仅需要安装一个大小为21M的.NET framework分发包,然后直接打开网页就可以进行工作。也没有操作系统限制,从windows 98到windows xp都能很好的支持。 伸缩性和安全性 伸缩性 由于采用的是XML标准数据格式作为中间数据交换,因此本解决方案具有非常好伸缩性,例如,客户端的.NET控件可以采用JAVA APPLET、ACTIVX或者是VB,VC等编写的客户端应用程序直接替换。服务器也可以任意选择采用IIS或APACHE等WEB服务器。数据库也可以采用任意一种数据库。包括SQL Server,Oracle或者是Access等。这点上文已经谈到过,因为文章的长一点并不会使送给我的T恤大一号,这里再强调一遍只是为了加深读者对XML的跨平台性的认识。 :) 安全性 由于采用的是普通WEB服务器传送数据,因此可以直接采用SSL安全套接字等已经成熟的WEB加密技术。同时还可以对XML进行数据算法加密,在客户端再进行解密,保证了传输的安全性。 由于采用的是80端口,不需要再另外新增加专用端口,减少了安全漏洞的可能性,同时还能方便的穿过双方的的网络防火墙等保护设备。 方案设计图 格式定义 为了能自己控制打印的格式,我们定义了下列的格式标签,其中在命名上参考了HTML的命名办法,所以基本上熟悉HTML的都能一看就能明白标签的具体含义。如果您觉得这些标签的表达能力还不够强,您还可以自己定义一些更多更精确的格式标签。 主要标签说明: text:文本字符串 属性: x:打印输出的X坐标 y:打印输出的Y坐标 fontname:字体 fontsize:字体大小 fontcolor:颜色 b:是否为粗体 i:是否为斜体 u:是否有下划线 table:表 属性: x:打印输出的x坐标 y:打印输出的y坐标 border:边框粗细 bordercolor:边框颜色 maxlines:每页最大行数 tr:行 属性: height:高度 td:列 属性: width:宽度 align:对齐方式 fontname:字体 fontsize:字体大小 fontcolor:字体颜色 b:是否粗体 i:是否斜体 u:是否下划线 bgcolor:背景颜色 next:下一页 tablehead:表头 tablebody:表项 tablefoot:表底 page:页设置 PrintWard:横/纵向打印 PageType:纸张类型 PageLeft:左边距 PageRight:右边距 PageTop:上边距 PageBottom:下边距 标签应用示例: <root> <pagesetting> <Landscape>true</Landscape> <paperkind>A4</paperkind> <paperwidth>210</paperwidth> <paperheight>297</paperheight> <pageleft>0</pageleft> <pageright>0</pageright> <pagetop>0</pagetop> <pagebottom>0</pagebottom> </pagesetting> <reporttable> <text x="450" y="40" fontname="黑体" fontsize="24" fontcolor="Black" b="true" i="false" u="true">最新成交合同信息</text> <text x="70" y="100" fontname="宋体" fontsize="12" fontcolor="Black" b="true" i="false" u="true">制表时间:2002年0月10日</text> <text x="910" y="100" fontname="宋体" fontsize="12" fontcolor="Black" b="true" i="false" u="true">单位:元</text> <table x="65" y="130" border ="1" bordercolor="Black" maxlines="28"> <tablehead> <tr height="25"> <td width="90" align="center" fontname="宋体" fontsize="12" fontcolor="Black" b="true" i="false" u="false" bgcolor="White">合同号</td> <td width="90" align="center" fontname="宋体" fontsize="12" fontcolor="Black" b="true" i="false" u="false" bgcolor="White">产品名称</td> <td width="50" align="center" fontname="宋体" fontsize="12" fontcolor="Black" b="true" i="false" u="false" bgcolor="White">成交量</td> <td......[阅读全文]

posted @ | Feedback (14) |

摘要: 专栏作品 续:利用XML实现通用WEB报表打印(实现篇)卢彦 引言: 在《利》刊出后,有大量的读者发E-Mail给我表示对该方案非常感兴趣,同时还询问具体如何实现报表格式的解析和打印细节并索取该程序的源代码。读者的热情让我始料未及,虽然我一一对来信进行解答和发送了源代码,但是还是深感抱歉和遗憾,因为时间和精力的关系,我不可能对每封信都作出很详细的答复,而且我写的源代码也很乱,事实上,是我花了两个小时赶写出来的(原来的程序因为硬盘故障被销毁了),不但没有什么注解而且还不完善,包括一些标签还没有被实现。 为了弥补以前的缺憾,我花了一些时间改进了程序的结构,重写了全部的源代码,实现了所有标签的功能,下面就要开始讲解该程序的设计和编码过程,在看此文之前,强烈推荐您先阅读《利》一文来了解一下相关的概念,如果在该文中已经有清楚讲解的部分,本文将不再详细介绍,这里只将主要讲解《利》文没有提及或是介绍得不清楚和读者来信提问最多的部分。 软件原理: 该软件的原理其实很简单,就是要方便的解析出定义好的XML格式标记,解读出文件中标记的参数定义,最后将这些信息还原成打印机输出的图形格式。 为了能表达出复杂的报表样式,我们需要定义一些标记,在这些标记中附加上具体的样式信息,作用类似HTML的标签,而我们的解析程序就相当于IE浏览器,所不同的是IE将图形输出到屏幕,而我们是将图形输出到打印机,由于打印机相对于显示屏的特殊性(例如分页),因此我们不能直接采用网页浏览器的标签解析功能来打印,需要自己来做一个满足需要的"打印浏览器"。 针对大多数报表的功能需要,我只定义了两种格式标签:文本(text)和表格(table),它们的具体属性定义和另外一些设置性的标签定义请参考《利》文,这里再补充一幅结构图帮助读者理解。如下所示: 结构设计: 为了描述所有的样式标记,我先定义了一个抽象基类PrintElement,它拥有一个虚拟方法Draw,然后对应表格和文本,从PrintElement派生出两个子类,分别是Table和Text,我还创建了一个Parser类用来解析不同的样式标记和创建对应的对象,它拥有一个静态的方法CreateElement,用来根据不同的格式标签创建出对应的对象。结构图如下所示: 读过《设计模式》的读者一定已经看出来了,这种设计应用了设计模式中的一个非常著名的模式:Abstract Factory。这里使用该模式的好处就是让标签对象和解析器都独立出来,降低了系统的耦合度,有利于今后在需要的时候可以很容易的增加其它的格式标签(下文将会举一个实例)和方便的更换不同的用户界面(图中Client表示Windows应用程序或者是网页插件)。 首先,创建一个"Windows控件库"的新项目,在项目名称处写入RemotePrint,如下图所示: 然后把新建项目中的那个默认的UserControl1类,它的构造函数名和文件名都改成PrintControl。再将它的背景颜色设置为白色,添加三个按纽,并将它们的Enable属性都设置为false,Anchor属性设置为Bottom, Right,再添加一个Label控件用来显示程序状态,它的Anchor属性设置为Left。如下图所示: 再从控件栏中拖入三个打印对象:PrintDocument, PageSetupDialog, PrintPreviewDialog,如下图所示: 将其中的pageSetupDialog1和printPreviewDialog1的Document属性均设置为printDocument1。 然后为项目添加一个PrintElement的新类,代码如下: using System; using System.Xml; using System.Drawing; namespace RemotePrint { public class PrintElement { public PrintElement() { } public virtual bool Draw(Graphics g) { return false; } } } 该类中只有一个虚拟方法Draw,注意它规定需要返回一个bool值,这个值的作用是用来指示标签是否在页内打印完毕。 然后再添一个Table的新类,代码如下: using System; using System.Xml; using System.Drawing; namespace RemotePrint { public class Table : PrintElement { private XmlNode table; public static int count = 0, pc = 1; public Table(XmlNode Table) { table = Table; } public override bool Draw(Graphics g) { //表格坐标 int tableX = int.Parse(table.Attributes["x"].InnerText); int tableY = int.Parse(table.Attributes["y"].InnerText); int x = tableX, y = tableY; DrawTopLine(g, table);//画表格顶线 Pen pen = new Pen(Color.FromName(table.Attributes["bordercolor"].InnerText), float.Parse(table.Attributes["border"].InnerText)); int trheight = 0; //表头 foreach(XmlNode tr in table["tablehead"].ChildNodes) { trheight = int.Parse(tr.Attributes["height"].InnerText); DrawTR(x, y, tr, pen, g); y += trheight; } //表项 for(int i = 0; i < int.Parse(table.Attributes["maxlines"].InnerText); i++) { XmlNode tr = table["tablebody"].ChildNodes[count]; trheight = int.Parse(tr.Attributes["height"].InnerText); DrawTR(x, y, tr, pen, g); y += trheight; count++; if(count == table["tablebody"].ChildNodes.Count) break; } x = tableX; //表底 foreach(XmlNode tr in......[阅读全文]

posted @ | Feedback (15) |

摘要: 专栏作品 利用GDI+的双缓冲技术来提高绘图效率卢彦 前言 进入.NET时代,Windows的绘图技术也从GDI升级到了GDI+,从名字就能知道GDI+是对以前传统GDI绘图技术的一次升级,不过在微软几乎把所有的新技术都冠之.NET的情况下,GDI+竟然不叫做GDI.NET,还真让我感到有点意外了。 :) GDI+在一种与设备无关的环境下提供了一套统一的绘图编程模型,极大的提高了Windows绘图编程的方便性,我们再也不用创建什么各种各样复杂的设备环境了,说实话,我现在想起来都头疼。 题归正传,关于如何进行GDI+的基本编程,我不能过多的加以描述,如果有对此概念还不太清楚的朋友,建议先去了解一下相关的资料,我们在这里主要讨论的是一种提高绘图效率(主要是动画效率)的双缓冲技术在GDI+中的应用和实现。 实现目的 为了能清楚的对比应用双缓冲技术前后的效果,我编写了一段程序来进行测试。首先,我创建了一个普通的Windows Application,在主Form中,我放置了一个定时器:timer1,然后将它的Interval属性设置为10,然后在Form上放置两个按纽,分别用来控制定时器的开启和关闭,最后,我还放置了一个label控件,用来显示绘图的帧数。 测试程序 在timer1的timer1_Tick事件中,我写下了如下的代码(其中flag是一个bool型标志变量): DateTime t1 = DateTime.Now; Graphics g = this.CreateGraphics(); if(flag) { brush = new LinearGradientBrush(new PointF(0.0f, 0.0f), new PointF(700.0f, 300.0f), Color.Red, Color.Blue); flag = false; } else { brush = new LinearGradientBrush(new PointF(0.0f, 0.0f), new PointF(700.0f, 300.0f), Color.Blue, Color.Red); flag = true; } for(int j = 0; j < 60; j ++) { for(int i = 0; i < 60; i++) { g.FillEllipse(brush, i * 10, j * 10, 10, 10); } } DateTime t2 = DateTime.Now; TimeSpan sp = t2 - t1; float per = 1000 / sp.Milliseconds; this.label1.Text = "速度:" + per.ToString() + "帧/秒"; 运行后,我点击“开始”按纽,效果如下图所示: 应用双缓冲以前的效果图(帧数:5帧/秒) 正如大家所看到的,我在程序中使用循环画了几百个圆形,然后在每次的定时器脉冲事件中使用不同方向的线性渐变来对它们进行填充,形成了一个动画效果。不过不幸的是,程序运行起来闪烁很严重,几乎每次刷新的时候都可以看到一条很明显的扫描线从上慢慢的刷到下来完成整幅图形的刷新动作。如果你不是要模拟老式雷达的区域扫描的话,这种速度不会满足你的要求。 改进代码 下面是我改进以后的代码: DateTime t1 = DateTime.Now; Bitmap bmp = new Bitmap(600, 600); Graphics g = Graphics.FromImage(bmp); if(flag) { brush = new LinearGradientBrush(new PointF(0.0f, 0.0f), new PointF(700.0f, 300.0f), Color.Red, Color.Blue); flag = false; } else { brush =......[阅读全文]

posted @ | Feedback (28) |

摘要: 专栏作品 对比.NET PetShop和Duwamish来探讨Ado.NET的数据库编程模式卢彦 .NET PetShop和Duwamish简单介绍 相信大家一定听说过有名的"宠物店大战",没错,本文的主角之一就是获胜方.NET PetShop,微软号称以27倍的速度和1/4的代码量遥遥领先于基于J2EE的PetStore宠物商店。虽然SUN也曾对此抱怨过不满,指责此"大战"有水分,不过无论如何,.NET PetShop绝对是一个经典的.NET实例教程,至少为我们提供了一条赶超J2EE的“捷径” :),它的下载地址是:http://www.gotdotnet.com/team/compare .NET PetShop宠物网上商店首页 而Duwamish则是一个外表简单,内部却极其复杂的一个网上书店的.NET完整应用范例,作为一个微软官方的Sample,它同时提供了C#和VB.NET两种语言版本,并且还附上了大量详尽的中文资料,如果打印出来,实在是居家旅行,临睡入厕必备之物。什么?您没听说过?呵呵,如果您装了Visual Studio .NET的话,它就在您的硬盘上静静的躺着呢,不过还没有被安装,您可以在您的VS.NET 的Enterprise Samples目录下找到并安装它,例如:C:\Program Files\Microsoft Visual Studio .NET\Enterprise Samples\Duwamish 7.0 CS。 Duwamish网上电子书店首页 结构简述 两家商店都采用了n层应用结构(毫无疑问,n层结构的应用架构应该绝对是您开发.NET应用的首选,哪怕您只想做一个网页计数器),不同的是,PetShop采用的是最常见的三层应用结构,分别为表示层,中间层和数据层。而Duwamish则采用的是一个四层应用结构,并使用不同的项目分隔开,分别为表示层,业务外观层,业务规则层和数据层。至于这两种结构分别有什么优点和缺点,以及为什么要这么分层,我们不进行详细讨论,因为本文的重点不在于此。我们主要分析的是他们的数据库编程的模式。 Duwamish数据访问剖析 首先,我们来看看Duwamish书店,它采用的是DataAdapter和DataSet配合的数据存储模式,所不同的是,它对DataSet进行子类化扩展作为数据载体,也就是采用定制的DataSet来进行层间的数据传输,下面是一个定制的DataSet示例: public class BookData : DataSet { public BookData() { // // Create the tables in the dataset // BuildDataTables(); } private void BuildDataTables() { // // Create the Books table // ......[阅读全文]

posted @ | Feedback (7) |

摘要: 专栏作品 设计模式:利用C#的Delegate来改进Observer模式卢彦 Observer模式简介 为了让更多的人能够看明白本文,所以在此之前,我们先来了解一下Observer模式的基本概念。 模式名称:Observer 结构图: 意图: 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。 适用性: 当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。 当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。 应用实例 在编写多层应用程序时,我们通常将表示层和数据逻辑层分隔开,比如很常见的View/Document结构,这种设计方式的好处带来的结果通常是使用多视图同时表示单一数据源,比如一个Web网站可以方便的同时拥有针对电脑的Html页面和针对手机的WAP页面。使用这种结构时,为了保持数据显示的一致性,必须要求数据源在数据发生改变时能及时的逐一通知每一个和它绑定的表示层进行更新。但是问题在于数据层本身并不知道到底有多少个不同的表示层正在反映着它的数据内容。因此需要设计一套有效的机制来完成这个目标。 模式实现 我们先看看来自《设计模式迷你手册》的常规的C#实现代码。 Subject(抽象目标): 目标知道它的观察者。可以有任意多个观察者观察同一个目标。 //实现代码 class Subject { //由于不知道有多少个观察者,所以建立了一个观察者链表 private ArrayList list = new ArrayList(); private string strImportantSubjectData = "Initial"; public string ImportantSubjectData { get { return strImportantSubjectData; } set { strImportantSubjectData = value; } } public void Attach(Observer o) { list.Add; o.ObservedSubject = this; } public void Detach(Observer o) { } public void Notify() { //在数据发生改变后遍历列表通知观察者 foreach (Observer o in list) { o.Update(); } } } Observer(抽象观察者): 为那些在目标发生改变时需要获得通知的对象定义一个更新接口。 abstract class Observer { //内置一个需要观察的对象 protected Subject s; public Subject ObservedSubject { get { return s; } set { s = value; } } abstract public void Update(); } ConcreteSubject(实体目标,在这里相当于数据逻辑层): 将有关状态存入各ConcreteSubject对象。 当它的状态发生改变时,向它的各个观察者发出通知。 //在这里基本上什么都没有做,数据的获取可以放到GetState()里面 class ConcreteSubject : Subject { public void GetState() { } public void SetState() { } } ConcreteObserver(实体观察者,在这里就相当于表示层): 维护一个指向ConcreteSubject的引用。 储存有关状态,这些状态应与目标的状态保持一致。 实现Observer的更新接口以使自身状态与目标状态保持一致。 class ConcreteObserver : Observer { private string observerName; public ConcreteObserver(string name) { observerName = name; } override public void Update() { //将数据显示出来 Console.WriteLine("In Observer {0}: data from subject = {1}", observerName, s.ImportantSubjectData); } } 主函数: public class Client { public static......[阅读全文]

posted @ | Feedback (1) |

摘要:自从.net推出以来,.net与java之间的明争暗斗就一直没有停息过,但是战斗一直都仅限于理论层面上,互相都只摆出自己的一堆大道理,口水都快淹死人了,但却从来没有真刀真枪的干上一仗。为什么呢?原因是.net一直在家里不出来,哪里都不去。他们没有机会真正的碰过面。但现在她们终于有机会真正进行一场公平的竞赛了,一年前就一定开始的.net开放源码计划MONO不久前刚刚推出了最新版本0.13,虽然还是个开发中的产品,但是我已经忍不住要把她请出来和java过过招了。再进行枯燥的数据对比以前,请先看一段浪漫的故事,了解一下.net,mono之间的关系,谢谢。 :)话说很java不服气,虽然java上门去找.net比划过几招,但是.net的父亲老比对她很不欢迎,而且好象也没比赢。Java很生气:"有什么了不起,不就是比我年轻几岁吗?老娘当年风光的时候你还没出生呢,只在家算什么厉害,在你们家我当然比不过你了,有种出来呀!"。这边老麦很是得意:"大家看看,我还当.net是什么大美女呢,连客都不敢见,多半笨得连话都说不清楚。看我们家java多好,人见人爱,上得厅堂下得厨房,让她去哪就去哪,半句都不罗嗦。"这边老比答话了:"谁说咱们家.net不行?她不仅系出名门,天资国色,而且能听懂几乎所有国家的语言,我还专门请了编织大师安德斯到我们家来专门教她刺绣。不过她是大家闺秀,岂能跟你们家那个野丫头一样到处乱跑,谁都可以摸一把。再说了,这里大部分的土地都属于我们家,她出不出去其实都一样。".net虽然生活无虑,每天有人伺候,但是还是经常照着镜子叹气:"唉,都怪我老爸,限制人家自由,虽然可以每天穿好衣服,但是只有我们家的人才能看到我,我想让世界上所有的人都来赞叹我的美丽,让各种人用不同的语言对我说:'我爱你'。"。.net的话有一天被一个英俊的小伙子听到了,他就是开发出了Linux下著名的x-windows系统gnome的ximian。他第一次见到.net就被她的美貌给深深打动了,他对身旁的人说:"我终于发现,她就是我真正想要的"。他还发现.net是microsoft家族中唯一一个想要出去的人。于是他每天抽空跟她讲一些发生在他们那里的美好的故事,讲他们那里有很多很多勤劳善良的人,那里没有等级,没有剥削,大家都无私的贡献出自己的劳动成果让大家一起来分享。都自觉的遵守着他们自己制定的平等的制度GNU,那个繁荣自由的国度就是Linux。"啊?Linux!".net吃惊的叫了起来,"我知道!我爸爸说那里是坏蛋居住的地方,那里的人们很穷,他们自己不知道怎么去赚钱维生,每天只想到去如何攻击掠夺别人的家园,还一直嚷嚷着要把我们的家给拆散,要把我们家里的东西全部抢走!""那些并不是真的"ximian平静的说:"我可以带你去那里看看,美丽的小姐,你会被他们的勤劳善良和伟大给感动的"。"真的吗?".net美丽的大眼睛里闪动着向往和好奇,然后坚定的说:"我一定要去那里看看,即使是父亲不允许,我也一定要去!"。当晚,.net脱下高贵的华服,换上粗陋的布衣,跟ximian出发了。此时,老比其实把一切都看在了眼里,但是他并没有阻止ximian,他叹了口气说道:"去吧,孩子,毕竟时代不一样了,你一定会成为我们家族最大的荣耀的"。同时,他的嘴角闪过了一丝不容易被察觉的微笑,精明的老比此刻正想着什么呢?故事还在发展,现在还看不到任何结局,.net在linux国度里改名叫做mono,她从最基本的开始学起,慢慢的适应了linux的生活,一年过去了,mono终于推出了最新的版本0.13,在这个版本里,我们看到了很多重要的进步,慢慢的开始显露出了.net的才华和美丽。下面,我们要做一些测试,看看.net是否真正的适应了linux的生活,和她原来比起来究竟有多大的差距,同时,我们还邀请到了java,做为友情客串,她只是提供一些参考性的测试数据。当然,这并不是一场和java很正式的比赛,有点难为mono了,毕竟,mono还只是一款正在开发中的产品。首先,我们来进行一个循环测试,循环测试被很多人指责太过于简单,不能很好的反映出真实的运行环境,但是它的优点也在于它的简单,因为程序越复杂,写法就越多,争论的焦点就变成了如何对程序进行最优化,例如著名的宠物店大战。同时也因为曾经有一个很有名的测试,是对一个jsp的循环速度测试,结果是jsp是7秒,asp和php都是80多秒,被java爱好者津津乐道了很久,我当时也用asp.net测试过是2秒,当然操作系统环境不一样,不具备太大参考价值。也是后话。下面是用于进行测试的程序,主要功能就是执行十亿次循环,循环里面有一个加法运算和一个赋值运算。硬件测试环境为:P3-M 1.2G, 512M, 30G(笔记本电脑)。软件测试环境为:Mono 0.13 for Linux, Mono 0.13 for Windows, .Net Framework SDK 1.0.3705(中文版), J2SE 1.4.0_01 for Linux,J2SE 1.4.0_01 for Windows, Windows操作系统为:Windows XP中文版,Linux操作系统为:Mandrake Linux 8.2。编译方式均采用默认选项。输出的结果均为运行所需时间,单位为毫秒。以下是该测试程序的C#程序代码:using System;class test{????static void Main(string[] args)????{?????? int temp;?????? DateTime a = DateTime.Now;?????? for(int i = 0; i < 1000000000; i++)?????? {?????????? temp = 1+1;?????? }?????? DateTime b = DateTime.Now;?????? TimeSpan c = b - a;?????? Console.WriteLine(c.TotalMilliseconds);????}}以下是相应的java程序代码:import java.util.Date;public class test{????public static void main(String args[])????{?????? Date before = new Date();?????? long a,b;?????? int temp;?????? a = before.getTime();?????? for(int i = 0; i < 1000000000; i++)?????? {?????????? temp = 1 + 1;?????? }?????? Date after = new......[阅读全文]

posted @ | Feedback (14) |