Programming C# - 行者无疆 始于足下 - 行走,思考,在路上

Programming C#

xiaohanyu posted @ Mon, 24 Jan 2011 14:41:55 +0800 in Web with tags ASP.NET .NET Sqlite c# , 5049 readers

1 课业要求

这半年有一门《C#程序设计》的课程,借着这个契机,匆匆学了下C#,并做了一个极其简陋的“大程”。

程序的要求基本如下:

  • 用C#实现一个数据库操作网页代码生成工具。需要实现的基本功能如下:
    1. 列出数据库中所有表供用户选择
    2. 用户选择一个表后生成若干网页,能对选定的表提供list、add、modify、delete等操作,不能使用GridView控件,需要用标准的HTML元素实现
    3. 能够分析表中每个字段的类型,在add、modify界面上根据字段的类型使用合适的Web组件,需要能正确处理数字、字符、日期等类型
    4. List的时候能够自动处理分页
    5. 为了提交作业方便,数据库使用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工具有sqlitebrowsersqliteman

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,对语言之争已经看的很淡,更谈不上对某一门语言的死忠。在我看来,学习一门编程语言只能有两个结果:

  1. 给你的编程思想打开了新的一道门;
  2. 让你明白或巩固一个道理: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。谢谢捧场。

Avatar_small
Lox said:
Mon, 24 Jan 2011 15:05:32 +0800

呃,is-programmer.com服务器的时间出问题了。比正常时间快了四个小时。

FAFA said:
Sun, 06 Mar 2011 08:37:05 +0800

我很喜欢你对C#的评论。

Firen said:
Sun, 06 Mar 2011 11:20:59 +0800

C#能做的东西,Java都能做到,而且能做的更好。求证明过程。

Avatar_small
Lox said:
Sun, 06 Mar 2011 11:56:37 +0800

没有必要这么钻牛角尖吧。这就比如“C语言能做的东西,汇编都能做”,类似。虽然C#和Java是属于同一层面的语言。

再说这是我的一家之言。对C#只是摸了一下表皮,并没深入其里,证明就算了。

Avatar_small
Lox said:
Sun, 06 Mar 2011 11:56:52 +0800

浅见。欢迎指教。

Avatar_small
Lox said:
Sun, 06 Mar 2011 12:08:02 +0800

另外,Java是跨平台的。而C#不是。凭这点可以给C#判死刑了。

FAFA said:
Mon, 07 Mar 2011 17:17:16 +0800

我是从88的LinuxDev版看到你的博客。然后把这篇文章地址贴到闪存了。后来想想我发的闪存内容有点“过激”,所以我又给删了。


Login *


loading captcha image...
(type the code from the image)
or Ctrl+Enter
Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee