Programming C# - 行者无疆 始于足下 - 行走,思考,在路上
Programming C#
1 课业要求
这半年有一门《C#程序设计》的课程,借着这个契机,匆匆学了下C#,并做了一个极其简陋的“大程”。
程序的要求基本如下:
-
用C#实现一个数据库操作网页代码生成工具。需要实现的基本功能如下:
- 列出数据库中所有表供用户选择
- 用户选择一个表后生成若干网页,能对选定的表提供list、add、modify、delete等操作,不能使用GridView控件,需要用标准的HTML元素实现
- 能够分析表中每个字段的类型,在add、modify界面上根据字段的类型使用合适的Web组件,需要能正确处理数字、字符、日期等类型
- List的时候能够自动处理分页
- 为了提交作业方便,数据库使用access,提供对话框让用户选择数据库
我大概花了一周左右的时间完成了程序,这其中包括:三天的时间熟悉C#和Mono,一天的时间复习SQL语法并学习Sqlite的使用,一天的时间学习下ASP.NET,一天时间完成程序,最后一天的时间用来看新版《水浒传》……^_。
最终的效果自然是十分“简陋”,只实现了第1、4、5条的需求和第2、3条的部分需求,而且还存在严重的bug。不过时间紧迫,加上我对微软的快餐文化无爱,就匆匆忙忙交了作业,忙下一门考试去了。
简单说下实现思路吧,顺便总结下学习C#过程中的一些心得。
实验的基本条件:
- OS: Arch Linux
- IDE: MonoDevelop 2.4.2
- Language: C# implemented by mono project
- Web Server: xsp implemented by mono project
- Database: Sqlite 3.7.4
2 Mono
引用mono-project主页上的说法,mono is "An open source, cross-platform, implementation of C# and the CLR that is binary compatible with Microsoft.NET", MonoDevelop is "An open Source C# and .NET development environment for Linux, Windows, and Mac OS X"。虽然在Linux下用Mono来搞C#是件不怎么“光彩”的事情,但是mono却给我留下了极佳的用户体验。代码补全、重构,多语言支持,内建xsp server,集成调试功能,还有让我欢呼流泪的Editor的Vi-mode的支持。
那么Mono到底是个什么东西呢?直白点的说法就是,Mono是Microsoft .NET的跨平台实现。比如我们可以用C#写如下一个程序winform.cs:
using System; using System.Windows.Forms; public class HelloWorld : Form { static public void Main() { Application.Run(new HelloWorld()); } public HelloWorld() { Text = "Hello, Mono World"; } }
程序的功能十分简单:创建一个窗口并将窗口标题设为"Hello, Mono World"。
我们用如下的命令编译运行此程序:
gmcs -pkg:dotnet winform.cs && mono winform.exe
然后屏幕上就会显示一个窗口。将winform.exe拷贝到一个装有.NET的windows中,程序也是可以运行的。
3 Sqlite
基于程序跨平台的考虑,C#的运行环境我选择了Mono,而数据库则抛弃了MicroSoft Access,选择了Sqlite,也借此契机学习下这个世界上最流行的嵌入式数据库引擎。
什么是嵌入式数据库?传统的数据库,如MySQL,采用的是Client/Server架构。而Sqlite采用的Serverless架构。Sqlite所有的读写都直接应用于一个跨平台的磁盘文件。Sqlite的特性有:
- ACID事务
- 零配置 – 无需安装和管理配置
- 储存在单一磁盘文件中的一个完整的数据库
- 数据库文件可以在不同字节顺序的机器间自由的共享
- 支持数据库大小至2TB
- 足够小, 大致3万行C代码, 250K
- 比一些流行的数据库在大部分普通数据库操作要快
- 良好注释的源代码, 并且有着90%以上的测试覆盖率
- 独立: 没有额外依赖
- Source完全的Open, 你可以用于任何用途, 包括出售它
- 支持多种开发语言,C, PHP, Perl, Java, ASP .NET,Python
Sqlite作为一个示范性的学习型开源项目也是一个非常理想的选择。在Sqlite的主页上有sqlite-amalgamation-3070400.zip下载,这是一个组合了所有Sqlite的C代码在一个单独文件中的压缩挡。是学习数据库设计与实现的极好资源。
Sqlite在很多著名的开源软件项目中都有重要的应用。引用《The Definisive Guide to Sqlite》中的一段话:
"If you are a programmer, imagine how much code it would take to implement the following SQL statement in your program:
SELECT AVG(z-y) FROM table GROUP BY x HAVING x > MIN(z) OR x < MAX(y) ORDER BY y DESC LIMIT 10 OFFSET 3;
If you are already familiar with SQL, imagine coding the equivalent of a subquery, compound query, GROUP BY clause or multiway join—in C. SQLite embeds all of this functionality into your application with minimal cost. With a database engine integrated directly into your code, you can begin to think of SQL as a domain-specific language in which to implement complex sorting algorithms in your program. "
记得大二下学期伊始学习Java,要编写一个浙江大学校车查询系统的软件,那个时候还没有学过数据库,就想破脑门地琢磨该怎么样采用Java实现复杂的校车查询算法,甚至想要去研究各种图论算法云云。直到两个月后学习了数据库原理,情况才逐渐明朗。最终的程序采用的是Apache Derby,另一款Java实现的嵌入式数据库。关于Sqlite和Derby的对比,可以参考Sqlite Versus Derby。
我们可以用如下的命令找出系统中的Sqlite数据库文件:
sudo updatedb && for file in `locate *.db` do file $file done | grep -i "sqlite" | awk '{print $1}'
Sqlite比较好用的GUI工具有sqlitebrowser和sqliteman。
Sqlite具有多种语言的bindings,关于C#的binding还有些小小的麻烦,因为Sqlite的binding并不是ECMA C#标准的一部分,所以MS C#和Mono C#对此的实现有些许差别。Mono通过Mono.Data.Sqlite实现访问Sqlite的ADO.NET,具体的示例代码如下所示:
- 通过IDataReader:
using System; using System.Data; using Mono.Data.Sqlite; public class Test { public static void Main (string[] args) { string connectionString = "URI=file:/home/lox/test.db"; IDbConnection dbcon; dbcon = (IDbConnection)new SqliteConnection (connectionString); dbcon.Open (); IDbCommand dbcmd = dbcon.CreateCommand (); // requires a table to be created named employee // with columns firstname and lastname // such as, // CREATE TABLE employee ( // firstname varchar(32), // lastname varchar(32)); string sql = "SELECT * " + "FROM test"; dbcmd.CommandText = sql; IDataReader reader = dbcmd.ExecuteReader (); while (reader.Read ()) { int FirstName = reader.GetInt32(0); string LastName = reader.GetString (1); Console.WriteLine ("Name: " + FirstName.ToString() + " " + LastName); } // clean up reader.Close (); reader = null; dbcmd.Dispose (); dbcmd = null; dbcon.Close (); dbcon = null; } }
- 通过DataSet:
using System; using System.Data; using System.Data.SqlClient; using Mono.Data.Sqlite; public class Test { public static void Main (string[] args) { string connectionString = "URI=file:/home/lox/user.db"; string commandString = "select * from py_phrase_0"; SqliteDataAdapter dataAdapter = new SqliteDataAdapter(commandString, connectionString); DataTable dataTable = new DataTable(); dataAdapter.Fill(dataTable); foreach (DataRow dataRow in dataTable.Rows) { Console.WriteLine(dataRow["phrase"].ToString()); } } }
话说ADO.NET的DataSet和ASP.NET中某些控件的bind功能还真是挺方便的。
4 ASP.NET
ASP.NET?这究竟是个什么东西?大一时学了一门课叫做《WEB数据库设计》,讲的是ASP,诸如如何配置IIS,如何在Dreamweaver中添加Access数据源、连接数据库,以及VBScript的入门语法等等。三年之后我才知道,IIS并不是Apache的对手,Apache在某些方面也不如nginx,LAMP架构才是web服务中基础中的基础;编写html最好用的不是Dreamweaver而是vim;Access充其量只是个不跨平台比Excel强点有限的玩具数据库产品;ASP日薄西山,已经i躺在了历史的博物馆里了;当初对ASP的吹嘘——动态网页技术,如今又成了ASP的最大诟病——代码混杂,无法分离网页设计和业务逻辑——而这又成了ASP.NET横空出世的理由。至于ASP.NET能活多久,我不关心也不在乎,我所在乎的只是用这个东西尽快地完成我的大程序。
理解ASP.NET的核心在于亮点,一是MVC架构的理解,即业务逻辑和页面表现的分离;二是Windows事件机制和消息循环机制。
MVC(Model, View, Control)是当今网站中比较流行的架构。其最大的贡献在于实现了网站业务逻辑与页面表现美工的分离。最初的动态网页,无论是ASP、JSP还是PHP也好,静态的html代码和程序语言代码混杂在一起,造成了大规模web程序非常难于书写和维护。后来Java出现了各种各样的框架如当下流行的SSH(Struts、Spring、Hibernate);微软革了ASP的命推出了ASP.NET,以C#和VB.NET为后端实现MVC架构;PHP也有各种各样现成的数不清的框架。框架这个东西是最容易过时的。所以我觉得框架这个东西就像山东大饼,饱腹可以,太过深究细节就有些得不偿失,重要的还是要掌握柴米油盐。用框架人人都会,但是设计并实现出一个优秀的框架,就不是嘴上说说那么容易了。微软的快餐产品让千百万人踏入了程序设计的大门,也让他们陷入了跟潮流的漩涡。而一切微软技术的核心,定有躲不开的核心,那就是Win32 API和消息循环机制。
深入探讨这个问题已经远远超出了本人的能力。本人也只是窥探了几章《Windows程序设计》,才到这里才大放厥词。什么是消息循环?事实上消息循环绝不向消息循环那么简单,消息循环和OO、结构化程序设计一样,是一种Architectural Patterns。常见的Architectural Patterns(参考Software Architecture in Practice (2nd Edition)有:
- Layered
- Generalization(OO)
- Pipe-and-filter
- Shared-data
- Publish-subscribe(event-based)
- Client-server
- Peer-to-peer
- Communicating process
- ……
消息循环属于Publish-subscribe,它是Windows事件机制的基础。而消息循环中很重要的两点一个是消息队列,另外就是Callback Functions(回调函数)。形像的讲,我们设每个事件为x,而处理事件x的函数为X。假设我们的一个系统软件依次出发a、b、c、d四个事件,那么消息队列中有abcd四个事件,然后由操作系统根据消息队列来决定下一步该做哪些事情。比如Windows看到了消息队列中的第一个事件为a,那么Windows就会调用A来处理事件a,a处理完毕后出队,接下来的事件是b,那么就调用B来处理时间b。没错,ABCD等Callback Function是有操作系统来调用,而不需要程序员在程序中显示调用,这也是它们被叫做Callback Function的原因。
理解消息循环对Windows程序设计是至关重要的,诸如MFC、C# Windows Forms和ASP.NET的所有事件处理机制都是基于消息循环。在一开始写GUI程序的时候常常程序的时候常常无法理解程序的执行流行,一来是结构化编程的思想根深蒂固,二来是没有完全理解Event-based程序的处理模式。那么另一个问题是,回调函数的机制又是怎样的呢?这个问题答案的关键字是函数指针,一个我们在C语言中学过、有点印象却很少用到的东西。函数指针也是C++多态性RTTI的关键所在!(参考《Thinking in C++, Volume 1》)。Java Swing的listener,QT的signal and slots机制,归根到底应该也是消息循环。Publish-subscribe, core of GUI programming。
差不多了。关于ASP.NET的絮叨到此为止吧,再下去就黔驴技穷了。如果再加一句,就是ASP.NET的控件还是挺好用的^_^。
5 C#
最后谈到C#。简单的说,C++和Java入门之后,完全没有必要再学C#。C#能做的东西,Java都能做到,而且能做的更好。也算学了若干门Programming Languages,对语言之争已经看的很淡,更谈不上对某一门语言的死忠。在我看来,学习一门编程语言只能有两个结果:
- 给你的编程思想打开了新的一道门;
- 让你明白或巩固一个道理:trade-off是很重要的!
很不幸,对我来说,C#属于第二种,而Python和Shell Script属于第一种。C语言是指针的艺术,C++则有试图设计一种智能指针,Java抛弃了指针,只有C#,哆哆嗦嗦地使用着指针:unsafe code和delegate;C#的继承控制更为复杂,除了传统的public、protected、private,还有internal和protected internal;Java用import,包和文件目录有统一的物理逻辑关系,C#用using,包和文件目录很混乱,这到底是个优点还是个缺点?C++的class和struct几乎相同,C#却限制了struct的使用;C#还有一种类成员get/set的语法,我觉得这种语法糖特别恶心。更多的语言特性比较可以参考http://tech.it168.com/a2010/0817/1091/000001091254.shtml。
写到这里我又想到,为什么会有如此多的Programmig Languages呢。假设把这些编程语言按照字母顺序排一下,让一个人去学,恐怕一辈子也学不完。github上有一个有趣的hello world项目,汇集了众多语言写的hello world程序,你可以通过如下命令获取这些程序:
git pull git://github.com/git/hello-world.git
面对如此多的编程语言,我们又该如何选择呢?著名黑客Eric Raymond给了我们有说服力的答案:
"It's best, actually, to learn all five of Python, C/C++, Java, Perl, and LISP. Besides being the most important hacking languages, they represent very different approaches to programming, and each will educate you in valuable ways."
没错。虽然说解决问题是最终目的,方法手段有千千万,语言不是关键,思想是最重要的,但是选择语言往往也决定着你的思想,就比如你不太可能去用Python lambda, map, reduce去实现Functional Programming,也不太可能用lisp去写OO程序等等。
6 Learning Resources
.NET语言并没有C++语言如《The C++ Programming Language》和《C++ Template》这种重量级的传世著作,O'Reilly的《Programmig C#》和《Programming ASP.NET》是非常不错的入门教材了。其余一切国内的中文xx教程、xx精通一虑不要看。
理解消息循环和Windows事件机制,最经典的莫过于Charles Petzold的《Programming Windows》,我虽然只看过前几章,但已经受益匪浅。
最终版的程序就不给了。区区几百行,bug一大堆,丢人的。如果实在有需要参考,可以给我发邮件。xiaohanyu1988@gmail.com。谢谢捧场。
Mon, 24 Jan 2011 15:05:32 +0800
呃,is-programmer.com服务器的时间出问题了。比正常时间快了四个小时。
Sun, 06 Mar 2011 08:37:05 +0800
我很喜欢你对C#的评论。
Sun, 06 Mar 2011 11:20:59 +0800
C#能做的东西,Java都能做到,而且能做的更好。求证明过程。
Sun, 06 Mar 2011 11:56:37 +0800
没有必要这么钻牛角尖吧。这就比如“C语言能做的东西,汇编都能做”,类似。虽然C#和Java是属于同一层面的语言。
再说这是我的一家之言。对C#只是摸了一下表皮,并没深入其里,证明就算了。
Sun, 06 Mar 2011 11:56:52 +0800
浅见。欢迎指教。
Sun, 06 Mar 2011 12:08:02 +0800
另外,Java是跨平台的。而C#不是。凭这点可以给C#判死刑了。
Mon, 07 Mar 2011 17:17:16 +0800
我是从88的LinuxDev版看到你的博客。然后把这篇文章地址贴到闪存了。后来想想我发的闪存内容有点“过激”,所以我又给删了。
Tue, 08 Mar 2011 11:54:00 +0800
那个版的闪存?
Thu, 27 Sep 2018 22:34:56 +0800
AVENGERS是一部適合所有戰鬥電影觀看者的好電影。他們這部電影的故事我很好,位置和演員都很棒。我喜歡這部電影的所有部分。感謝您為我們分享這篇文章。