有几位高手在留言里提醒我, 把几个概念搞混了. 其实概念我是明白的, 只不过我想, 这个文章肯定不是那种有 "前言" 和 "参考文献" 清单的技术论文, 而更多是为了表达我在试用linq----2sql, 不好意思, 差一点又混淆了视听----时, 对MS所做的一些工作的敬佩, 以及解决了我积累多时的技术问题时所感觉到的那种快意和激动, 因此甚至连很多拼写错误也没有纠正, 大家都是搞技术的, 相信不会不理解我的意思.
但是, 为了表示对大虾们意见的重视, 我这就把文章里的模糊化的概念和名词加一括号注释, 以免误导读者. 如果您已经被本文误导, 兹向您表示深切的(但是肚子里憋着笑的)歉意.
-------------------------------------------------------------------------------------------
多年了,没有什么技术再能让我激动得无法控制住自己,包括WPF的超炫界面功能,我也只是小小地喜悦了一下,但毕竟知道界面设计更多还是美工创意的功夫,见过很多品味不够的开发人员,把自己程序界面搞得花里胡骚,简直得像不小心坐在调色板上的大熊的屁股,只能让人笑话。所以WPF的UI能力似乎离自己还有距离。
但是,Linq(其实是LINQ2SQL和C#3.0里的一些新语法),却真得把我雷到了。在我重新坐下来写这段话之前,我是激动得在屋里转了几圈的,嘴里至少把MS骂了十来句“WC!”,这骂不是怀了恨意的骂,而是怀了敬意的骂,是没办法控制自己兴奋和激动的心情的骂,就像是《朱罗纪公园》里的马尔康姆教授第一眼看到人工DNA造出来的活恐龙时,说的那句话:“这帮狗娘养的真的做到了!”
我,未能免俗,被MS绝对好用的IDE拖住了,从VC(++)5.0开始, 一路上了MS的套, 直追到C#3.(0, .net3.5), 每一代的技术都让人目瞪口呆, 但每一次又都如过眼云烟, 还没有来得及完全消化, 下一个版本时就已经被全然抛弃了. 在.net 1.0 时, 我跟着MS去用服务器控件和Dataset, 还没有玩热, 2.0里已经开始在推datasou(r)ce, 其实我想datasou(r)ce里一定会有很精深的东西, 但是我也没来得及好好看时, LINQ(2sql)已经出现了.
其实不能怪MS把自己的技术追随者随意抛弃, 凭心而论, MS这几年是太进取了, 太希望把新的技术推出来了. 因为那些中间阶段的技术, 虽然都能让人有醍醐灌顶的感觉, 但是真得实用起来时, 总是会有一些这样那样的问题, 或是不方便之处. 于是, 每次MS推出一个新技术时, 都能让我感觉恰好解决了一直困扰我的一些问题. 看看MS在为了解决企业应用上做的努力吧: ASP.net用服务器控件的方式来简化BS应用的开发, 不方便, 改用vs2003的智能客户端(这时还需要用自己写程序集加载功能), 还不方便, 在vs2005中智能客户端已经一键部署了, 还是不方便, 然后, VS2008里WPF出现, 用BS的方法开发和使用程序, 但像CS应用一样运行, 您满意了吗?
再看ORM方面的努力. .net1.0时, MS请我用dataset和dataadapter, 那已经比SQL方便了不了啦! 只不过我是一个OOP纯粹主义者, 不太喜欢用数据表的方式考虑问题, 然后, MS开始允许让我把 IEnum(e)rable 型也做为数据源, 也一样可以绑定数据控件. 只是让我痛苦的是对象不会自动地保存到数据库中, 我试过流行的开源ORM框架, 也痛苦地写了自己的代码生成器从表结构来生成类定义和CRUD的方法. 但还是总是会遇上一些问题.
然后, LINQ出现了, System.Data.Linq(也就是linq2sql) 也出现了.
第一次尝试(linq2sql)时, 我向dbml(linq2sql类设计器)中拖了一个表格, 然后, 我被雷到了第一次: 它生成了我一直在找但一直没有找到的那个类, 还有我之前不止一次梦想过的数据上下文类!(我知道, 我知道, Hibernate也是可以的, 但是我真得记不住他的配置方法.)
然后我向dbml(linq2sql类设计器)中放进去了更多的表, 然后, 我被雷到了第二次: 它根据我的表关联关系自动为我配置好了对象聚合! 我试着查询了一下产品对象, 然后, 通过产品对象的定单成员, 我可以直接检索这个属于产品的定单了.
在通读了几篇LINQ(2sql, 这些文章的作者也没有刻意去区别这个差别, 包括MSDN上的一些作者, 我替他们再向各位道歉)的内容之后, 我决定我的下一个项目用LINQ(2sql)来做. 然后, 一如即往的, 在实际的使用中遇上了一堆问题. 第一个问题是我想扩展数据类的定义, 增加自己的新属性和方法什么的, 然后, 我发现只要一动设计图, 我所有的新代码都不见了! 还好用了VSS, 立即签回上一个版本. 那该怎么办呢, 难道不能修改这些美妙的类定义?
然后, 我想过用extender, 用继承, 但是都像之前的各种MS迫不及待地推给我的技术一样, 虽然也能解决问题, 但都很勉强. 去MSDN一查, 他们建议我另建一个源文件, 用partail(partial)类的方式来扩展这些类, 自己写的partail(partial)类不会被设计器乱改. 他妈的! 居然这么简单! 我我我, 唉, 我真傻, 真的,我只知道Winform design的时候可以用到partail(partial)类, 不知道在linq(2sql)里也可以用到的...
这个问题解决了, 感觉自己连气出得都痛快了. 但是随即又遇上一个问题: 我想在数据加载时偷偷做些自己的处理, 这该怎么办? 我在智能感知的菜单里去找闪电图标, 希望找到一个DataLoaded事件让我订阅一下, 然后, 没有! 试着打个override来看看有没有OnLoaded之类的虚拟方法让我重写一下. 然后, 也没有! 好好, 我还有一大堆办法可以解决, 我可以在select之后再调用个成员方法来预处理. 目的是达到了, 但是, 代码好丑! MS就打算让我这么做? MS这回是怎么回事? 明明一个delegate就可以解决的, 非要我写这么丑的代码.
真得不服气呀! 我再去找! 然后, 就看到那一堆堆的 partial void OnLoaded()方法定义. 这是什么东西? 方法也可以partail吗? OnLoaded()明显是我想要的东西, 但是这个partial表示什么? 老了老了, 很多东西没功夫好好看了.
于是, 上MSDN上一找, 又被雷到了!
MSDN上是这么写的:
分部类或结构可以包含分部方法。类的一个部分包含方法的签名。可以在同一部分或另一个部分中定义可选实现。如果未提供该实现,则会在编译时移除方法以及对方法的所有调用。
看看,看看! 如果未提供该实现, 则会在编译时移除方法以及对方法的调用! 老天呐!!! 事件委托时还要写一个 "if (Data_Loaded != null)" 的, 现在只需要一个partail 方法? 继续向下看, MSDN又说:
分部方法使类的某个部分的实施者能够定义方法(类似于事件)。类的另一部分的实施者可以决定是否实现该方法。如果未实现该方法,编译器将移除方法签名以及对该方法的所有调用。因此,分部类中的任何代码都可以随意地使用分部方法,即使未提供实现也是如此。如果调用了未实现的方法,将不会导致编译时错误或运行时错误。
在自定义生成的代码时,分部方法特别有用。这些方法允许保留方法名称和签名,因此生成的代码可以调用方法,而开发人员可以决定是否实现方法。与分部类非常类似,分部方法使代码生成器创建的代码和开发人员创建的代码能够协同工作,而不会产生运行时开销。
说实话, 到这时我已经基本被雷晕了, 我理想中的那种完美方案完全如希望的样子出现了, 不, 这样的代码实现, 干净利落得远远超出我的期望. 我于是开始站起来在屋里乱走, 一边用脏话来发泄心里的激动. 就是我在本文一开始说的那样. 明白吗? 这是在编译时处理的, 是源代码上的方法模板模式实现! 这还是一个编译器该做的吗? 你允许我用匿名类型的局部变量, 我就已经很感激了(自从泛型引入以后, 我就总是猜不中我该用什么类型来接收模板方法的返回值), 现在, 你开始允许我在源码上瞎写不存在的方法了!
文章写到现在, 激动的心情已经平静不少, 一个担心开始出现了: MS的C#接下来还将怎样进一步允许我们胡闹?
我的一个开发员, 无论做什么功能, 都用datasoure实现, 他只会 "拖控件, 拖数据源, 配置数据源", 然后, 他在代码里一遍一遍地执行绑定, 完全不管数据库已经被查询了多少次. MS的技术越来越不要求严谨, 越来越纵容程序员胡来(在语言规范越来越灵活的同时, 向java一样强制要求处理异常的机制却一直没有增加就是一个例子), 在MS的强大的编译技术保护下, 还会有多少程序员变成傻瓜?