We do not always find visible happiness in proportion to visible virtue

梦幻白桦林

SHARE

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  14 Posts :: 58 Stories :: 62 Comments :: 0 Trackbacks

公告

常用链接

留言簿(5)

搜索

  •  

最新随笔

最新评论

阅读排行榜

2009年4月25日 #

    .net 中Unit已经标记了Serializable了
  [Serializable]
    [TypeConverter(
typeof(UnitConverter))]
    
public struct Unit
    {
}

我定义了个类,其中有个width属性

        Unit width;

        [DefaultValue(
typeof(Unit), "")]
        [Bindable(
true)]
        [Description(
"列宽")]
        
public Unit Width
        {
            
get { return width; }
            
set { width = value; }
        }
序列化后为<Width/>
posted @ 2009-04-25 17:00 colys 阅读(1428) | 评论 (3)编辑 收藏

从字符串中取出包含的函数名和所有参数你这样:[method("arg1",arg2,...n个)]

要求:

以[开头,]结尾

method 为 sum , count ,page, eval  其中的一个

可以没有括号,比如[page]

参数可以有引号,也可以没有引号,参数不限个数,比如:
[sum("Money")]    要能取出 sum, Money
[count(0)]   要能取出 count, 0
[eval("aa",1)] 要能取出 eval aa,1

posted @ 2009-04-25 15:56 colys 阅读(2115) | 评论 (6)编辑 收藏

2007年11月21日 #

福鼎白茶
白茶属微发酵茶,是我国六大类茶叶中的一颗璀璨明珠,中国是白茶的惟一产地。白茶的品质特征为:成茶披满白毫,十分素雅,汤色清淡,味鲜醇、清甜、有毫香。基本加工工艺流程是萎调、晒干或低温烘干。因采用鲜叶原料不同,故可分为:白毫银针、白牡丹、贡眉、寿眉及新工艺白茶五种。生产白茶对品种和加工工芤要求十分严格,适制白茶的茶树品种为:福鼎大白茶、福鼎大毫茶、政和大白茶和闽北水仙等。白茶是我国历史名茶,其主产区在福建省福鼎市、政和县,建阳、建瓯等县市也有少量生产。据茶叶史料记载,白茶首创于福建省福鼎县,又据福建省地方志编委会出版的《福建地方志》和现代茶叶著名专家张天福教授的《福建白茶的调查研究》及清代明人周亮工《闽小记》的记载,清喜庆初年(公元1796年),福鼎人用菜茶(有性群体种)的壮芽为原料,创制白毫银针。在1857年,福鼎大白茶茶树品种从太姥山移植到福鼎县点头、柏柳等地选育成功,由于福鼎大白茶芽壮、毫显、香高,所制白毫银针外型品质远远优于“菜茶”。于是福鼎茶人改用福鼎大白茶的壮芽为原料制造“白毫银针”,出口价高于原菜茶加工的银针(后来称土针)10多倍。约在1860年,“土针”逐渐退出“白毫银针”的历史舞台。据《福建地方志》记载,政和县1880年选育繁殖成功“政和大白茶”品种,1889年开始产制银针。两地生产银针时间相距约80多年。总之,白茶类中是先有“银针”,后才有白牡丹、贡眉、寿眉,至于新工艺白牡丹,是二十世纪70年代由原福鼎茶厂白琳分厂研制的一个新的白茶产品。所以说,白茶之所以能自成一类,是因其具有独特的产地(区域)、独特的品种和独特的加工工艺,离开其中任何一个因素都生产不出好茶。同时,生产白茶具有很大的风险性,表面上看加工工艺二十简单,但其内在的技术要领二十不易掌握。

天山绿茶

天山绿茶是福建省的历史名茶,为闽东烘青绿茶的极品。品质特优,尤其是里、中、外天山所产的绿茶品质更佳,称之“正天山绿茶”。
据《宁德县志》记载,天山绿茶曾经历一段变革演化过程。宋代生产团茶、饼茶,也生产乳茶、龙团茶。到了元、明代生产“茶饼”,供作礼品和祭祀品。公元1781年前后,天山所产的芽茶已被列为贡品。明、清以后,以生产炒青条形茶为主。几经变革,到了1979年,才改制为烘青型绿茶,成为高档花茶的优质原料。历史上,天山绿茶花色品种丰富多彩,而今,除少数花色品种失传外,大多数传统花色品种,如天山雀舌、凤眉、明前、清明等均得到恢复,并创制了新的品种,如清水绿、天山毛峰、天山银毫、四季春、毛尖等。这些绿茶以锋苗挺秀、香高、味浓、色翠、耐泡五大特点赢得了荣誉。从1979年恢复生产以来,曾多次在地、省及全国名茶评选会上获奖,名列前茅。天山银毫茉莉花茶在全国内销花茶评比会上,名列第一。1982年、1986年二次被评为全国名茶,商业部授于全国名茶荣誉证书。
天山位于东海之滨,天山主峰——屏南天湖山,屹立在福建省屏南、宁德、古田三县交界的屏南黛溪乡。除天湖山外,还有天峰山、仙峰山、大坪山等山脉,是天山绿茶的原产地。这里山峰险峻,海拔1300米左右,林木参天,云海翻滚,气候温和,年均气温15℃左右,年降雨量1900毫米左右,土壤肥沃湿润,多为结构疏松的砂质壤土。茶树多生长在岩间和山坡上,树壮芽肥,是适制天山绿茶的理想原料。难怪诗人赞道:“深山奇石嵯峨立,峡谷悬崖味茶香”。
天山绿茶采用的原料因花色品种不同而异。如雀舌和凤眉等传统珍品,选用叶质肥厚、持嫩性强的天山菜茶品种的芽叶为原料。采摘标准为一芽一叶和一芽二叶初展。制500克干茶约需3万个左右芽叶。新创制的名茶如清水绿等,则选取大、中叶种的芽叶为原料,采摘标准以一芽二叶初展为主,制500克干茶需7000个左右芽叶。
天山绿茶实现了机械化生产。主要设备有连续滚筒电热恒温杀青机,40型或45型揉捻机,自动百叶烘干机等。加工工艺有凉青、杀青、揉捻、烘干(毛火和足火)四道工序。杀青掌握“高温、控热、少量、短时”的方法。筒温240~260℃,电热控制,前高后低。起锅摊凉散热后再行揉捻。揉捻时采用“小机、适量、轻压、短揉”的技术措施,达到条索紧结、色泽翠绿、香味清鲜的目的。40型揉捻机投叶量7.5~10公斤,45型揉捻机投叶量10~12.5公斤。转速55转C分。烘干毛火掌握“薄摊、高温、快烘”的原则。足火掌握低温慢烘,达到干度内外均匀一致,香高而鲜爽的目的。毛火烘温115℃左右,含水量15~20%。足火烘湿90~95℃,含水量6%左右。
天山绿茶具有“三绿”特色,即色泽翠绿,汤色碧绿,叶底嫩绿,且外形条索嫩匀、锋苗挺秀、茸毫显露,香似珠兰花香,芬芳鲜爽,滋味浓厚回甘,犹如新鲜橄榄,汤色清澈明亮,经泡耐饮,冲泡3~4次,茶味犹存。饮之幽香四溢,齿颊留芳,令人心旷神怡

福鼎白琳工夫茶
"白琳工夫茶"充分发挥福鼎大白茶的特点,精选细嫩芽叶,制成工夫茶,外形条索紧结纤秀,含有大量的橙黄白毫,具有鲜爽愉快的毫香,汤色、叶底艳丽红亮,取名为「桔红」,意为桔子般红艳的工夫,风格独特,在国际市场上很受欢迎。
"白琳工夫茶"系小叶种红茶,当地种植的小叶群体种具有茸毛多、萌芽早、产量高的特点,一般的白琳工夫,外形条索细长弯曲,茸毫多呈颗粒绒球状,色泽黄黑,内质汤色浅亮,香气鲜纯有毫香,味清鲜甜和,叶底鲜红带黄。
"白琳工夫"为三大闽红工夫之一,以其独特风格和品质盛兴百年而不衰。白琳功夫茶采用福鼎大白茶代替原有的小叶种,成为加工白琳功夫的主要原料,使其质量有了显著的提高。它的品质特征,几乎代表白琳功夫高级茶的独特风格,在国际市场上很受欢迎。主要特点是:条索紧结,茶毫显露金黄色,干茶色泽乌润油亮,汤色红艳明亮,叶底红亮,滋味鲜浓醇爽,香气清高,有特殊的花香,耐冲泡,既适合清饮,又适合掺和砂糖、牛奶。

福鼎莲心茶
莲心茶形似莲子瓣心而得名,为我国传统名茶。产于福建省太姥山麓的福鼎百琳和霞浦水门。太姥山景色秀丽,崖林之间茶树丛主。相传,早在光绪年间,太姥山麓的白琳一带,茶树已广为种植。到了本世纪30年代,莲心茶以茶中珍品闻名海内外。用莲心茶窨制成茉莉娥眉、茉莉秀眉,为花茶中的佼佼者,深受东南亚侨胞的喜爱。

莲心茶采取福鼎大白茶的一芽二叶为原料。经萎凋、杀青、揉捻、干燥等四道工序加工而成。

萎凋:目的在于蒸发部分水分,促使芽叶内含物发生适度的变化,消除成品的苦涩味。当地的经验是萎凋应掌握适当的限度,萎凋程度过轻达不到萎凋的目的;萎凋程度过重,即失水过多,内含物质变化过大,均不利莲心茶品质的形成。通常,芽叶减重率控制在18%左右,时间6~8小时。当叶色转为暗绿,叶的侧脉折而不断,折梗尚能脆断,叶质柔软,即为适度。

杀青:手工杀青,全用抖炒。做到抖得散,翻得匀。杀青锅温180℃左右,投叶量1500克左右,当叶子松散不粘手,清香透露即为适度。

揉捻:杀青叶经摊凉冷却后进行揉捻。达到茶索挺直紧结的目的。

干燥分毛火和足火两个过程。毛火在烘笼上进行,烘温90~100℃,每笼投叶量1500克左右,烘至七、八成干为适度。足火在炒锅内进行,锅温80℃左右,炒至足干,色略显灰为适。

莲心茶的品质特点是,外形细紧纤秀,锋苗显露,色泽绿中带黄,有似莲子蕊色,香气清幽,含绿豆清香,味醇鲜爽,汤色橙绿清澈,叶底嫩匀成朵。泡在杯中,两叶相对而开,中间竖一芽心,犹如莲子瓣心,颇有情趣。

福安坦洋工夫红茶
  坦洋工夫分布较广,主产福安、柘荣、寿宁、周宁、霞浦及屏南北部等地。坦洋工夫源于福安境内白云山麓的坦洋村,相传清咸丰、同治年间(公元1851 --1874年),坦洋村有胡福四(又名胡进四)者,试制红茶成功,经广州运销西欧。很受欢迎,此后茶商纷纷入山求市,接踵而来并设洋行,周围各县茶叶亦渐云集坦洋.坦洋工夫名声也就不胫而走,自光绪六年 至民国二十五年(公元1881—1936年)的50余年, 坦洋工夫每年出口均上万担,其中1898年出口3万余组。

  坦洋街长一公里,设茶行达36家,雇工3000余人,产量2万余担。收条范围上至政和县的新村,下至霞浦县的赤岭,方圆数百里,境跨七、八个县,成为福安的主要红茶产区。运销荷兰、英国、日本、东南亚等二十余个国家与地区,每年收外汇茶银百余万元。当时民谚云:“国家大兴,茶换黄金,船泊龙凤桥, 白银用斗量。”后因抗日战争爆发,销路受阻,生产亦遭严重破坏,坦洋工夫产量锐减。

  50年代中期,为了恢复和提高坦洋工夫红茶的产量和品质,先后建立了国营坦洋、水门红茶初制厂和福安茶厂,实行机械化制茶,引进并繁殖福鼎大白茶、福安大白茶、福云等优良茶树品种,1960年产量增加到5万担,创历史最高水平。后因茶类布局的变更,由“红”改“绿”,坦洋工夫尚存无几。近年来,经有关部门的努力,坦洋工夫又有所恢复和发展,1988年产量达8000余担。

  坦洋工夫外形细长匀整,带白毫,色泽乌黑有光,内质香味清鲜甜和,汤鲜艳呈金黄色,叶底红匀光滑。其中坦洋、寿宁、周宁山区所产工夫茶,香味醇厚,条索较为肥壮,东南临海的霞浦一带所产工夫茶 色鲜亮,条形秀丽。
posted @ 2007-11-21 21:47 colys 阅读(1412) | 评论 (1)编辑 收藏

2007年10月8日 #

#1  Web 2.0 编程思想:16条法则

原文:Thinking in Web 2.0: Sixteen Ways
作者:Dion Hinchcliffe
URL:http://sd.csdn.net/n/20060518/90603.html

1、在你开始之前,先定一个简单的目标。无论你是一个Web 2.0应用的创建者还是用户,请清晰的构思你的目标。就像“我需要保存一个书签”或者“我准备帮助人们创建可编辑的、共享的页面”这样的目标,让你保持最基础的需求。很多Web 2.0应用的最初吸引之处就是它的简单,避免并隐藏了那些多余的复杂性。站在创建者的立场,可以想象Google的几乎没有内容的主页,还有del.icio.us的简单的线条。从最终用户的角度来看,与之齐名的就是Diggdot.us所提供的初始化页面。你能够并且希望加入更多功能,但是先做好最开始的。在一个时候只做一个特性,完成一个目标。这听起来很太过于单纯化了,但它将使你更加专注,而且你也会明白我的意思。

2、链接是最基础的思想。这就是我们称之为Web的一个理由。链接是把Web中各种实体连接起来的最基本的元素。你的信息、你的关系、你的导航,甚至是能够被写成URL的任何内容。这里有一个链接应该遵循的规则(其实你也不必严格的遵守):

??? 1. Web上的任何东西都是可以被URI或者是URL所连接的。
??? 2. 把所有的链接都保存为他的原始出处,这样可以让你与任何人、在任何地方、任何时候都能分享它。
??? 3. 第二条中任何时候的前提是链接必须是持久的,它不会在没有任何缘由的情况下被改变或者是消失。
??? 4. 链接应该是人类可读的、稳定的、并且能够自我诠释的。

3、数据应该属于创建它的人。是的,你听我的。任何用户创建的、贡献的或分享的都是他们自己的,除非他们很明显的放弃这个权力来让你自由处置。他们贡献到Web上的任何信息都应该是可编辑的、能被删除的、并且能够取消共享,无论在任何时候,只要用户愿意。这也包含了那些间接的数据,像他们所关心的记录、日志、浏览历史、网站访问信息,或者是任何可以被跟踪的信息。所有的网站必须清晰简单的陈诉那些信息是用户创建的,并且提供他们停止创建的方法,甚至是清除的方法。

4、数据优先,体验与功能其次。无论它是文本、图片、音频还是视频,Web最终还是把这些解析为数据。换句话说,你无法脱离数据去呈现内容。所有这些数据都通过那些易于发现的URL来定位(参见第2条)。通过另一种形式来看待这些,Web最终是名词优先,动词其次,虽然最近正在向动词偏移。来看看名词的例子:日历的条目、家庭照片、股票价格。还有一些动词的例子:定一个约会、共享一张图片、买一份股票。

5、做好积极分享一切的准备。尽可能的分享一切,你所拥有的所有数据,你所提供的所有服务。鼓励不遵循原有意图的使用,提倡贡献,不要那些需要分享的内容坚持设置为私有的。在分享与发现之后,提供易于使用的浏览方式是显而易见的需求。为什么呢:话说回来,你会从别人的共享之中受益匪浅。注意:这里没有许可让你去侵犯版权保护的法律,你不能够去分享你刻录的DVD或者是拥有商业版权音乐,因为你已经同意不会去分享这些东西。但是你可以发现并分享那些完全开放的媒体内容。一个小小的建议,你可以学习一下Creative Commons license(共创协议).

6、Web是一个平台;要让它成长。当然,我们还有很多其他的平台(Windows、Linux、Mac),但是那些已经不是重点了。换句话说,Web是无法脱离的平台,不会中断的平台,你可以通过各种方式去扩展的平台。你在Web上提供的数据与服务将会成为Web一部分,最终你会在Web平台的某一处扮演你的角色。扮演好你的角色并照顾好后来者。

7、理解与信奉“阶梯性”。现在的Web越来越大,几乎蔓延到了全世界的所有国家,并且已经拥有了10亿用户。我的观点是Web的各个组成部分存在着细微的区别和不同,就像不同地方的用户那样。例如Web的设计部分:易用性永远优先于速度、可靠性、重用性与可集成性。你也应该提供同样的体验给你的用户。它已经被一次又一次的被人们在文档中强调,忠诚的用户很快会成为专业的用户,他们期待更快的速度还有更多。退一步支持他们。同样,也有很多很多的用户会进入这个阶梯的底端,如你所期待的那样。他们可能不会说你的语言,不熟悉你的文化,甚至不知道是如何到这里的。所以你需要向他们表达清楚。

8、任何东西都是可编辑的。或者是它应该被编织的更好。要确定的是,只有很少的东西是不能被编辑的,剩下的都可以,这是一个可写的Web。这并不意味着原始内容的丢失,而通常被理解为用户能够很容易的对内容加以评论,或者评注内容是在那里发现的。如果你对此应用的好,他们能够比你所想象的做的更多(把内容串起来并且给予原始内容来创建自己的,等等)。

9、Web上的身份是神圣的。不幸的是,这并不意味着你能够得到更多的隐私(这完全是上个世纪的想法)。但对身份的验证是必要的,你应该感谢那些只需一个邮件地址就能确定你身份的服务。这意味只要你对你的用户承诺了,你就必须保证他们的隐私安全。必要的时候,在这个世界的某处你还得为你的用户挺身而出,向当地的权威挑战。如果你没有打算那样做,你就得把实际情况告诉你的用户。另一方面,如果身份是必须的,不要试图伪装它,不然在某一天我们将会在Web上放弃我们的最后一点点隐私的权利。

10、了解流行的标准并且使用他们。从一个消费者或者是创作者的立场来看,数据将会以不同的格式与任何一个人交换。同时这样的数据也会反过来促进标准的完善与采纳。这通常意味像RSS、 OPML、XHTML、Simple XML、JSON等简单标准的流行,而避免SOAP、XSD,还有RDF、ATOM也一样,使用它们会给我的内心带来痛苦。请你也为你所钟爱的标准投上一票来支持它们。

11、遵循无意使用的规律。如果你把非常有趣的数据和服务用广泛使用的格式开放和共享出去,你将会得到你所应得的,其他人也将会基于你的那一块Web平台来构建。或许还会从别人那里得到更多,所以为这个做一下准备比较好。我已记不清有多少次我看到一个播客(podcasting)服务因为流行过渡而导致服务垮掉,就是因为他们被 Slashdot和del.icio.us给收录了。这一点要知道:网络上的大量化意味着如果一个内容非常有趣,即使是一个很小的角落也会得到惊人的访问量。鼓励使用这种方式,它还是非常有价值的,前提是你要有所准备。

12、粒化你的数据与服务。我们应该在很早以前就明白这些,大规模集成的数据仅仅适用于无需管理的下载与批量操作。分解你的数据,让他们独立成可描述的URL地址,对你的服务也一样。反过来说,你不要创建一些巨大的、复杂的、像圣诞树那样的数据结构和服务。保持简单,要非常的简单。让这些分离的片断能够容易的被重组和发现。

13、提供用户能够单独受益的数据和服务。渐渐依赖于这种社会化参与是存在风险的,你需要让你的用户有一点点动机来贡献时间、热情和信息,除非他们能够直接受益。社会化分享比个体行为的利益大很多,除非你能够激发用户的个人动机,否这你将无法享受这份厚礼。

14、让用户组织并过滤信息。不一定是必须的,但却是非常重要的。让用户以他们自己的方式来标注和组织数据,因为你自己是永远无法及时的处理他们的。用户会按照他们自己理解的最佳方式来处理并构建。要保证你的Web服务能够按照用户所需所想的方式来工作。这也是标签(tagging)和通俗分类(folksonomies )的方式如此成功的主要因素。

15、提供丰富的用户体验。Web一直都在和本地的应用程序进行着激烈的竞争。为什么?因为本地程序还是感觉上好一些,速度也快一些。但是这不会长久的(确信在5年或者15年后,这种竞争就不存在了)。是的,我在谈论Rich Internet Applications, Ajax, 还有那些不可思议的交互应用。他们让Web成为了一个真正的“无平台”的平台,如果你知道我是怎么想的。

16、信奉并支持快速改进和反馈。这个通常意味着加快步伐,但也意味着使用轻量级的工具、技术和不要做出那些适得其反的痛苦决定(例如使用一个被层层环绕的Ajax框架来代替可以通过混合来实现的,或者用C++来构建所有的东西,其实使用Ruby会更好一些)。这同时也意味着需要一个非常快速的方式来处理错误报告,修复Bug,释放新版本。从一个用户的角度来看,报告你所发现的任何问题,还有那些你经常抱怨的地方,甚至那些都不是一个Bug。

当然,Web 2.0是一个极其广泛和深奥的话题,没有一个人能够列举出它的所有重点和特征。如果你对此充满了兴趣,请花一点时间来补充我没有提到的地方。我想这就是Web 2.0的参与性吧! 
posted @ 2007-10-08 11:43 colys 阅读(340) | 评论 (0)编辑 收藏

2007年8月24日 #

http://www.cnblogs.com/hardrock/archive/2006/08/18/480668.html
posted @ 2007-08-24 10:29 colys 阅读(442) | 评论 (0)编辑 收藏

2007年7月3日 #

VS2005进行Web调试的浏览器选择
不幸,安装了firefox后,安装VS2005,VS进行web调试时就用了firefox而不是ie,这应该是默认浏览器搞的

更改方法:

打开 C:\Documents and Settings\Administrator\Local Settings\Application Data\Microsoft\VisualStudio\8.0\browsers.xml

 
<?xml version="1.0" ?> 
<BrowserInfo>
<Browser>
  
<Name>firefox.exe</Name> 
  
<Path>"F:\PROGRA~1\MOZILL~1\FIREFOX.EXE"</Path> 
  
<Resolution>0</Resolution> 
  
<IsDefault>False</IsDefault> 
  
</Browser>
<Browser>
  
<Name>Microsoft Internet Explorer</Name> 
  
<Path>"C:\Program Files\Internet Explorer\iexplore.exe"</Path> 
  
<Resolution>0</Resolution> 
  
<IsDefault>True</IsDefault> 
<DDE>
  
<Service>IExplore</Service> 
  
<TopicOpenURL>WWW_OpenURL</TopicOpenURL> 
  
<ItemOpenURL>"%s",,0xffffffff,3,,,,</ItemOpenURL> 
  
<TopicActivate>WWW_Activate</TopicActivate> 
  
<ItemActivate>0xffffffff,0</ItemActivate> 
  
</DDE>
  
</Browser>
<InternalBrowser>
  
<Resolution>0</Resolution> 
  
<IsDefault>False</IsDefault> 
  
</InternalBrowser>
  
</BrowserInfo>
将第一个<Browser>结点,也就是firefox的<IsDefault>改为 False ,将 IExplore 的一个改为True
或者直接删除此文件
posted @ 2007-07-03 22:25 colys 阅读(1342) | 评论 (0)编辑 收藏

2007年7月1日 #

一、异步IO
        对于应用程序而言,有两种类型的IO调用:即同步IO 与异步IO。其本质的区别是:同步IO会block当前的调用线程,而异步IO则允许发起IO请求的调用线程继续执行,等到IO请求被处理后,会通知调用 线程。在windows平台上,应用程序可以调用CreateFile API, 并通过设置FILE_FLAG_OVERLAPPED标志来决定是否发起异步IO请求。
        对于异步的IO请求,其最大的好处是:慢速的IO请求相对于应用程序而言是异步执行,这样可以极大提高应用程序的处理吞吐量。发起IO请求的应用程序需要关心的是IO执行完成的结果,而不必忙等IO请求执行的过程。
       事实上,无论对于同步IO,还是异步IO,当IO请求发送到device driver后,device driver的执行总是异步的,当它接到IO请求之后,总会马上返回给IO System。而IO System是否立即返回给调用线程,则取决于FILE_FLAG_OVERLAPPED标志的设置,如下图:


二、异步IO的同步问题。
        我们使用异步IO,是为了提高应用程序的处理吞吐量。但是,当异步IO不再异步时(无论你是否设置FILE_FLAG_OVERLAPPED标志),应用 程序的性能会受到极大的影响。根据Microsoft Knowledge Base 156932, 在下列几种情况下,异步IO会失去它的异步性,而表现出同步的性质:
1)如果文件使用了NTFS compression压缩,则system driver不会异步地存取这样的文件。
2)扩展文件长度的IO操作不会是异步操作。
3)Cache机制。如果IO操作使用了file system cache,则这样的IO操作会被当成同步IO,而非异步IO。
即使你使用了FILE_FLAG_OVERLAPPED标志。在这种情况下,
a.如果需要读取的数据已经在Cache里,那么I/O drivers会认为这样的IO请求可以被立即处理,其结果是ReadFile 或者WriteFile调用返回TRUE,表示是:同步处理完成。
b. 如果需要读取的数据不在Cache里,windows NT的file system是使用page-faulting机制来实现cache管理,而page-faulting总是被同步处理, Windows NT没有提供异步的page-faulting机制。的确, file system driver使用了线程池来缓解这一问题,但是,当应用程序发起的IO请求足够多时,线程池还是不能应付的。
        在我们开发基于异步IO应用程序时,应该避免上述问题的出现,因为它们会使程序的性能大打折扣。
那么,对于Cache,我们如何避免呢?答案是:请使用FILE_FLAG_NO_BUFFERING标志。这个标志会使异步IO真实地异步执行。
三、性能的测试数据(仅供参考)。
      我在我的机器上,简单地对使用FILE_FLAG_NO_BUFFERING标志的异步IO,与不使用FILE_FLAG_NO_BUFFERING标志的异步IO进行了对比。
操作:顺序读取1G的文件。
x轴表示:每次读取的字节数(单位:K/每次)
Y轴表示:读取完成所需要的时间。(单位:millisecond)
注意:每次测试读取的内容总数是相等的(1000M)。
例如:如果每次读取128k,则需要读取8000次(128k*8000 = 1000M)。
如果每次读取256k,则需要读取4000次(256k*4000 = 1000M)。
粉红色的线没有使用FILE_FLAG_NO_BUFFERING标志,而黄色的线使用了FILE_FLAG_NO_BUFFERING标志。

从以上的数据,我们可以得出以下结论:
1) 当使用FILE_FLAG_NO_BUFFERING标志,应用程序的性能会极大提高,大概有50%的提高。
2) 在使用异步IO的时候,还有一个注意的问题是:当你每次读取的字节数增大的时候,性能也会提高。尤其在小于1024k时,当增大次读取的字节数,性能都有 明显的提高。在混合了网络传输等复杂因素的应用程序开发过程中,建议将该值设置为可配置的参数,通过调整该参数,使你的应用达到最好的性能。

参考资料:

1) Microsoft Knowledge Base 156932

2)  Microsoft Windows Internals, Fourth Edition.

posted @ 2007-07-01 21:23 colys 阅读(724) | 评论 (0)编辑 收藏

2007年6月3日 #


有5户人家A,B,C,D,E,每户人家都养了5只鸽子,一共25只。

这5户人家想从一共这25只鸽子中挑出飞的最快的前5只鸽子。

大家选定了一个出发点和到达点,每次只能放飞5只鸽子,在这样情况下可以看到每次从出发地到目的地5只鸽子到达的先后顺序,但是没有计时器来计算时间。

注:题目中不要考虑鸽子体能,是否匀速,是否直线飞行等等情况,可以理想设定速度均匀而且稳速。
==============================================

请问:
A)在确保能挑出25只鸽子中飞的最快的5只的前提下,最少需要多少次比赛(每次只能5只)能保证能挑出最快的5只。

B)怎样比赛?
posted @ 2007-06-03 16:34 colys 阅读(1740) | 评论 (15)编辑 收藏

2007年5月27日 #

  在运行vs2003安装时老提示我是要更新还是删除,我都还没装怎么会有这个项呢!后来仔细看了看这个提示是属于我装的一个极点输入法的! 卸载掉后安装正常!

  事情可不是都那么顺,安装后运行一切正常,欣喜.....花了我好多时间!
但不过多久,在下一次开机后,它罢工了! 提示DI.DLL找不到! 多次运行还是如此! 想都不想,重装! 又是一阵等待...
再运行,oh,shit "找不到.dll 文件"

  无语..难道这就是microsoft的东东吗? 为什么以前安装和使用就没遇到这问题吗? 突然一个思想在我脑海里浮现,既然安装和输入法会有关,但运行会不会也如此!但极点五笔不是被我卸载掉了吗? 难道是五笔加加的问题?(我装有两个五笔输入法~~) 于是乎卸载掉五笔加加!再装吧...等待...

终于.....正常了...感慨ing.....................

posted @ 2007-05-27 23:50 colys 阅读(454) | 评论 (0)编辑 收藏

2007年5月18日 #

本文讨论:

• 用于编写单元测试的 NUnit
 
• 用于创建代码文档资料的 NDoc
 
• 用于生成解决方案的 NAnt
 
• 用于生成代码的 CodeSmith
 
• 用于监视代码的 FxCop
 
• 用于编译少量代码的 Snippet Compiler
 
• 两种不同的转换器工具:ASP.NET 版本转换器和 Visual Studio .NET 项目转换器
 
• 用于生成正则表达式的 Regulator
 
• 用于分析程序集的 .NET Reflector
 

本文使用了下列技术:

.NET、C# 或 Visual Basic .NET、Visual Studio .NET

除非您使用能够获得的最佳工具,否则您无法期望生成一流的应用程序。除了像 Visual Studio®.NET 这样的著名工具以外,还可以从 .NET 社区获得许多小型的、不太为人所知的工具。在本文中,我将向您介绍一些目前可以获得的、面向 .NET 开发的最佳免费工具。我将引导您完成一个有关如何使用其中每种工具的快速教程 — 一些工具在许多时候可以使您节约一分钟,而另一些工具则可能彻底改变您编写代码的方式。因为我要在本篇文章中介绍如此之多的不同工具,所以我无法详尽讨论其中每种工具,但您应该了解到有关每种工具的足够信息,以便判断哪些工具对您的项目有用。


本页内容
 Snippet Compiler 
 Regulator 
 CodeSmith 
 生成自定义模板 
 NUnit 
 编写 NUnit 测试 
 FxCop 
 Lutz Roeder 的 .NET Reflector 
 NDoc 
 NAnt 
 实际运行的 NAnt 
 转换工具 
 小结 

Snippet Compiler
Snippet Compiler 是一个基于 Windows® 的小型应用程序,您可以通过它来编写、编译和运行代码。如果您具有较小的代码段,并且您不希望为其创建完整的 Visual Studio .NET 项目(以及伴随该项目的所有文件),则该工具将很有用。

例如,假设我希望向您说明如何从 Microsoft?.NET 框架中启动另一个应用程序。在 Snippet Compiler 中,我将通过新建一个能够创建小型控制台应用程序的文件开始。可以在该控制台应用程序的 Main 方法内部创建代码片段,而这正是我要在这里做的事情。下面的代码片段演示了如何从 .NET 框架中创建记事本实例: 

System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName= "notepad.exe";
proc.Start();
proc.WaitForExit();

当然该代码片段本身无法编译,而这正是 Snippet Compiler 的用武之地。图 1 显示了 Snippet Compiler 中的这一代码示例。


按此在新窗口打开图片
图 1 Snippet Compiler


要测试该代码片段,只须按 play(运行)按钮(绿色三角形),它就会在调试模式下运行。该代码片段将生成一个弹出式控制台应用程序,并且将显示记事本。当您关闭记事本时,该控制台应用程序也将关闭。

就我个人而言,我是在尝试为某位向我求助的人士创建一个小型示例时,才发现 Snippet Compiler 是如此宝贵的 — 如果不使用该工具,则我通常必须新建一个项目,确保每个部分都能编译通过,然后将代码片段发送给求助者,并删除该项目。Snippet Compiler 使得这一过程变得更加容易、更加愉快。

Snippet Compiler 由 Jeff Key 编写,并且可以从 http://www.sliver.com/dotnet/SnippetCompiler 下载。

返回页首
Regulator
Regulator 是最后一个添加到我的头等工具清单中的。它是一种很有特色的工具,能够使生成和测试正则表达式变得很容易。人们对正则表达式重新产生了兴趣,因为它们在 .NET 框架中受到很好的支持。正则表达式用来基于字符、频率和字符顺序定义字符串中的模式。它们最常见的用途是作为验证用户输入有效性的手段或者作为在较大字符串中查找字符串的方法 — 例如,在 Web 页上查找 URL 或电子邮件地址。

Regulator 使您可以输入一个正则表达式以及一些针对其运行该表达式的输入内容。这样,在应用程序中实现该正则表达式之前,您可以了解它将产生什么效果以及它将返回哪些种类的匹配项。图 2 显示了带有简单正则表达式的 Regulator。

文档中包含该正则表达式 — 在该示例中,它是 [0-9]*,应该匹配一行中任意数量的数字。右下侧的框中含有针对该正则表达式的输入,而左下侧的框显示了该正则表达式在输入内容中找到的匹配项。在这样的单独应用程序中编写和测试正则表达式,要比尝试在您的应用程序中处理它们容易得多。

Regulator 中的最佳功能之一是能够在 regexlib.com 搜索联机正则表达式库。例如,如果您在搜索框中输入字符串“phone”,您将找到 20 种以上能够匹配各种电话号码的不同的正则表达式,包括用于英国、澳大利亚的表达式以及其他许多电话号码。Regulator 由 Roy Osherove 编写,并且可以在 http://royo.is-a-geek.com/regulator 下载。

返回页首
CodeSmith
CodeSmith 是一种基于模板的代码生成工具,它使用类似于 ASP.NET 的语法来生成任意类型的代码或文本。与其他许多代码生成工具不同,CodeSmith 不要求您订阅特定的应用程序设计或体系结构。使用 CodeSmith,可以生成包括简单的强类型集合和完整应用程序在内的任何东西。

当您生成应用程序时,您经常需要重复完成某些特定的任务,例如编写数据访问代码或者生成自定义集合。CodeSmith 在这些时候特别有用,因为您可以编写模板自动完成这些任务,从而不仅提高您的工作效率,而且能够自动完成那些最为乏味的任务。CodeSmith 附带了许多模板,包括对应于所有 .NET 集合类型的模板以及用于生成存储过程的模板,但该工具的真正威力在于能够创建自定义模板。为了使您能够入门,我将快速介绍一下如何生成自定义模板。

返回页首
生成自定义模板
CodeSmith 模板只是一些可以在任意文本编辑器中创建的文本文件。它们的唯一要求是用 .cst 文件扩展名来保存它们。我将要生成的示例模板将接受一个字符串,然后基于该字符串生成一个类。创建模板的第一步是添加模板头,它可声明模板的语言、目标语言以及简要模板说明: 

<%@ CodeTemplate Language="C#"    
   TargetLanguage="C#" 
   Description="Car Template" %>

模板的下一部分是属性声明,在这里可声明将在模板每次运行时指定的属性。就该模板而言,我要使用的唯一属性只是一个字符串,因此属性声明如下所示: 

<%@ Property Name="ClassName" Type="String" Category="Context" 
    Description="Class Name" %>

该属性声明将使 ClassName 属性出现在 CodeSmith 属性窗口中,以便可以在模板运行时指定它。下一步是实际生成模板主体,它非常类似于用 ASP.NET 进行编码。您可以在图 3 中查看该模板的主体。[编辑更新 — 6/16/2004:图 3 中的代码已被更新,以便对多线程操作保持安全。]

正如您所见,该模板接受字符串输入并使用该类名生成单独的类。在模板主体中,使用与 ASP.NET 中相同的起始和结束标记。在该模板中,我只是插入属性值,但您还可以在这些标记内部使用任意类型的 .NET 代码。在该模板完成之后,您就可以通过双击它或者从 CodeSmith 应用程序中打开它将其加载到 CodeSmith 中。图 4 显示了已经加载到 CodeSmith 中的该模板。

您可以看到左侧的属性正是我在该模板中声明的属性。如果我输入“SingletonClass”作为类名,并单击 Generate 按钮,则将生成图 3 的底部显示的类。

CodeSmith 使用起来相当容易,如果能够正确应用,则可以产生一些令人难以置信的结果。面向代码生成的应用程序中最常见的部分之一是数据访问层。CodeSmith 包括一个名为 SchemaExplorer 的特殊的程序集,可用来从表、存储过程或几乎任何其他 SQL Server? 对象生成模板。

CodeSmith 由 Eric J. Smith 编写,并且可以在 http://www.ericjsmith.net/codesmith 下载。

返回页首
NUnit
NUnit 是为 .NET 框架生成的开放源代码单元测试框架。NUnit 使您可以用您喜欢的语言编写测试,从而测试应用程序的特定功能。当您首次编写代码时,单元测试是一种测试代码功能的很好方法,它还提供了一种对应用程序进行回归测试的方法。NUnit 应用程序提供了一个用于编写单元测试的框架,以及一个运行这些测试和查看结果的图形界面。

返回页首
编写 NUnit 测试
作为示例,我将测试 .NET 框架中 Hashtable 类的功能,以确定是否可以添加两个对象并且随后检索这些对象。我的第一步是添加对 NUnit.Framework 程序集的引用,该程序集将赋予我对 NUnit 框架的属性和方法的访问权。接下来,我将创建一个类并用 TestFixture 属性标记它。该属性使 NUnit 可以知道该类包含 NUnit 测试: 

using System;
using System.Collections;
using NUnit.Framework;

namespace NUnitExample
{
    [TestFixture]
    public class HashtableTest {
        public HashtableTest() {
            
        }
    }
}

下一步,我将创建一个方法并用 [Test] 属性标记它,以便 NUnit 知道该方法是一个测试。然后,我将建立一个 Hashtable 并向其添加两个值,再使用 Assert.AreEqual 方法查看我是否可以检索到与我添加到 Hashtable 的值相同的值,如下面的代码所示: 

[Test]
public void HashtableAddTest()
{
    Hashtable ht = new Hashtable();
            
    ht.Add("Key1", "Value1");
    ht.Add("Key2", "Value2");

    Assert.AreEqual("Value1", ht["Key1"], "Wrong object returned!");
    Assert.AreEqual("Value2", ht["Key2"], "Wrong object returned!");
}

这将确认我可以首先向 Hashtable 中添加值并随后检索相应的值 — 这是一个很简单的测试,但能够表现 NUnit 的功能。存在许多测试类型以及各种 Assert 方法,可使用它们来测试代码的每个部分。

要运行该测试,我需要生成项目,在 NUnit 应用程序中打开生成的程序集,然后单击 Run 按钮。图 5 显示了结果。当我看到那个大的绿色条纹时,我有一种兴奋和头晕的感觉,因为它让我知道测试已经通过了。这个简单的示例表明 NUnit 和单元测试是多么方便和强大。由于能够编写可以保存的单元测试,并且每当您更改代码时都可以重新运行该单元测试,您不仅可以更容易地检测到代码中的缺陷,而且最终能够交付更好的应用程序。


按此在新窗口打开图片
图 5 NUnit


NUnit 是一个开放源代码项目,并且可以从 http://www.nunit.org 下载。还有一个优秀的 NUnit Visual Studio .NET 外接程序,它使您可以直接从 Visual Studio 中运行单元测试。您可以在 http://sourceforge.net/projects/nunitaddin 找到它。有关 NUnit 及其在测试驱动开发中的地位的详细信息,请参阅文章“Test-Driven C#: Improve the Design and Flexibility of Your Project with Extreme Programming Techniques”(MSDN ®Magazine 2004 年 4 月刊)。

返回页首
FxCop
.NET 框架非常强大,这意味着存在创建优秀应用程序的极大可能,但是也同样存在创建劣质程序的可能。FxCop 是有助于创建更好的应用程序的工具之一,它所采用的方法是:使您能够分析程序集,并使用一些不同的规则来检查它是否符合这些规则。FxCop 随附了由 Microsoft 创建的固定数量的规则,但您也可以创建并包括您自己的规则。例如,如果您决定所有的类都应该具有一个不带任何参数的默认构造函数,则可以编写一条规则,以确保程序集的每个类上都具有一个构造函数。这样,无论是谁编写该代码,您都将获得一定程度的一致性。如果您需要有关创建自定义规则的详细信息,请参阅 John Robbins 的有关该主题的 Bugslayer 专栏文章(MSDN ® Magazine 2004 年 6 月刊)。

那么,让我们观察一下实际运行的 FxCop,并且看一下它在我一直在处理的 NUnitExample 程序集中找到哪些错误。当您打开 FxCop 时,您首先需要创建一个 FxCop 项目,然后向其添加您要测试的程序集。在将该程序集添加到项目以后,就可以按 Analyze,FxCop 将分析该程序集。图 6 中显示了在该程序集中找到的错误和警告。

FxCop 在我的程序集中找到了几个问题。您可以双击某个错误以查看详细信息,包括规则说明以及在哪里可以找到更多信息。(您可以做的一件有趣的事情是在框架程序集上运行 FxCop 并查看发生了什么事情。)

FxCop 可以帮助您创建更好的、更一致的代码,但它无法补偿低劣的应用程序设计或非常简单拙劣的编程。FxCop 也不能替代对等代码检查,但是因为它可以在进行代码检查之前捕获大量错误,所以您可以花费更多时间来解决严重的问题,而不必担心命名约定。FxCop 由 Microsoft 开发,并且可以从 http://www.gotdotnet.com/team/fxcop 下载。

返回页首
Lutz Roeder 的 .NET Reflector
下一个必不可少的工具称为 .NET Reflector,它是一个类浏览器和反编译器,可以分析程序集并向您展示它的所有秘密。.NET 框架向全世界引入了可用来分析任何基于 .NET 的代码(无论它是单个类还是完整的程序集)的反射概念。反射还可以用来检索有关特定程序集中包含的各种类、方法和属性的信息。使用 .NET Reflector,您可以浏览程序集的类和方法,可以分析由这些类和方法生成的 Microsoft 中间语言 (MSIL),并且可以反编译这些类和方法并查看 C# 或 Visual Basic ®.NET 中的等价类和方法。

为了演示 .NET Reflector 的工作方式,我将加载和分析前面已经显示的 NUnitExample 程序集。图 7 显示了 .NET Reflector 中加载的该程序集。


按此在新窗口打开图片
图 7 NUnitExample 程序集


在 .NET Reflector 内部,有各种可用来进一步分析该程序集的工具。要查看构成某个方法的 MSIL,请单击该方法并从菜单中选择 Disassembler。

除了能够查看 MSIL 以外,您还可以通过选择 Tools 菜单下的 Decompiler 来查看该方法的 C# 形式。通过在 Languages 菜单下更改您的选择,您还可以查看该方法被反编译到 Visual Basic .NET 或 Delphi 以后的形式。以下为 .NET Reflector 生成的代码: 

public void HashtableAddTest()

    Hashtable hashtable1;
    hashtable1 = new Hashtable();
    hashtable1.Add("Key1", "Value1");
    hashtable1.Add("Key2", "Value2");
    Assert.AreEqual("Value1", hashtable1["Key1"], 
       "Wrong object returned!");
    Assert.AreEqual("Value2", hashtable1["Key2"],
       "Wrong object returned!");
}

前面的代码看起来非常像我为该方法实际编写的代码。以下为该程序集中的实际代码: 

public void HashtableAddTest()
{
    Hashtable ht = new Hashtable();
            
    ht.Add("Key1", "Value1");
    ht.Add("Key2", "Value2");

    Assert.AreEqual("Value1", ht["Key1"],
        "Wrong object returned!");
    Assert.AreEqual("Value2", ht["Key2"],
        "Wrong object returned!");
}

尽管上述代码中存在一些小的差异,但它们在功能上是完全相同的。

虽然该示例是一种显示实际代码与反编译代码之间对比的好方法,但在我看来,它并不代表 .NET Reflector 所具有的最佳用途 — 分析 .NET 框架程序集和方法。.NET 框架提供了许多执行类似操作的不同方法。例如,如果您需要从 XML 中读取一组数据,则存在多种使用 XmlDocument、XPathNavigator 或 XmlReader 完成该工作的不同方法。通过使用 .NET Reflector,您可以查看 Microsoft 在编写数据集的 ReadXml 方法时使用了什么,或者查看他们在从配置文件读取数据时做了哪些工作。.NET Reflector 还是一个了解以下最佳实施策略的优秀方法:创建诸如 HttpHandlers 或配置处理程序之类的对象,因为您可以了解到 Microsoft 工作组实际上是如何在框架中生成这些对象的。

.NET Reflector 由 Lutz Roeder 编写,并且可以从 http://www.aisto.com/roeder/dotnet 下载。

返回页首
NDoc
编写代码文档资料几乎总是一项令人畏惧的任务。我所说的不是早期设计文档,甚至也不是更为详细的设计文档;我说的是记录类上的各个方法和属性。NDoc 工具能够使用反射来分析程序集,并使用从 C# XML 注释生成的 XML 自动为代码生成文档资料。XML 注释仅适用于 C#,但有一个名为 VBCommenter 的 Visual Studio .NET Power Toy,它能够为 Visual Basic .NET 完成类似的工作。此外,下一版本的 Visual Studio 将为更多语言支持 XML 注释。

使用 NDoc 时,您仍然在编写代码的技术文档,但您是在编写代码的过程中完成了文档编写工作(在 XML 注释中),而这更容易忍受。使用 NDoc 时,第一步是为您的程序集打开 XML 注释生成功能。右键单击该项目并选择 Properties | Configuration Properties | Build,然后在 XML Documentation File 选项中输入用于保存 XML 文件的路径。当该项目生成时,将创建一个 XML 文件,其中包含所有 XML 注释。下面是 NUnit 示例中的一个用 XML 编写了文档的方法: 

/// <summary>
/// This test adds a number of values to the Hashtable collection 
/// and then retrieves those values and checks if they match.
/// </summary>
[Test]
public void HashtableAddTest()
{
    //Method Body Here
}

有关该方法的 XML 文档资料将被提取并保存在 XML 文件中,如下所示: 

<member name="M:NUnitExample.HashtableTest.HashtableAddTest">
  <summary>This test adds a number of values to the Hashtable collection
    and then retrieves those values and checks if they match.</summary> 
</member>

NDoc 使用反射来考察您的程序集,然后读取该文档中的 XML,并且将它们进行匹配。NDoc 使用该数据来创建任意数量的不同文档格式,包括 HTML 帮助文件 (CHM)。在生成 XML 文件以后,下一步是将程序集和 XML 文件加载到 NDoc 中,以便可以对它们进行处理。通过打开 NDoc 并单击 Add 按钮,可以容易地完成该工作。

在将程序集和 XML 文件加载到 NDoc 中并且使用可用的属性范围自定义输出以后,单击 Generate 按钮将启动生成文档资料的过程。使用默认的属性,NDoc 可以生成一些非常吸引人并且实用的 .html 和 .chm 文件,从而以快速有效的方式自动完成原来非常乏味的任务。

NDoc 是一个开放源代码项目,并且可以从 http://ndoc.sourceforge.net 下载。

返回页首
NAnt
NAnt 是一个基于 .NET 的生成工具,与当前版本的 Visual Studio .NET 不同,它使得为您的项目创建生成过程变得非常容易。当您拥有大量从事单个项目的开发人员时,您不能依赖于从单个用户的座位进行生成。您也不希望必须定期手动生成该项目。您更愿意创建每天晚上运行的自动生成过程。NAnt 使您可以生成解决方案、复制文件、运行 NUnit 测试、发送电子邮件,等等。遗憾的是,NAnt 缺少漂亮的图形界面,但它的确具有可以指定应该在生成过程中完成哪些任务的控制台应用程序和 XML 文件。注意,MSBuild(属于 Visual Studio 2005 的新的生成平台)为每种健壮的生成方案进行了准备,并且由基于 XML 的项目文件以类似的方式驱动。

返回页首
实际运行的 NAnt
在该示例中,我将为前面创建的 NUnitExample 解决方案创建一个 NAnt 版本文件。首先,我需要创建一个具有 .build 扩展名的 XML 文件,将其放在我的项目的根目录中,然后向该文件的顶部添加一个 XML 声明。我需要添加到该文件的第一个标记是 project 标记: 

<?xml version="1.0"?>
<project name="NUnit Example" default="build" basedir=".">
    <description>The NUnit Example Project</description>
</project>

项目标记还用于设置项目名称、默认目标以及基目录。Description 标记用于设置该项目的简短说明。

接下来,我将添加 property 标记,该标记可用于将设置存储到单个位置(随后可以从文件中的任意位置访问该位置)。在该例中,我将创建一个名为 debug 的属性,我可以随后将其设置为 true 或 false,以反映我是否要在调试配置下编译该项目。(最后,这一特定属性并未真正影响如何生成该项目;它只是您设置的一个变量,当您真正确定了如何生成该项目时将读取该变量。)

接下来,我需要创建一个 target 标记。一个项目可以包含多个可在 NAnt 运行时指定的 target。如果未指定 target,则使用默认 target(我在 project 元素中设置的 target)。在该示例中,默认 target 是 build。让我们观察一下 target 元素,它将包含大多数生成信息: 

<target name="build" description="compiles the source code">
</target>

在 target 元素内,我将把 target 的名称设置为 build,并且创建有关该 target 将做哪些工作的说明。我还将创建一个 csc 元素,该元素用于指定应该传递给 csc C# 编译器的数据。让我们看一下该 csc 元素: 

<csc target="library" output=".\bin\debug\NUnitExample.dll" 
    debug="${debug}">
<references>
    <includes name="C:\program files\NUnit V2.1\bin\NUnit.Framework.dll"/>
</references>
    <sources>
       <includes name="HashtableTest.cs"/>
    </sources>
</csc>

首先,我必须设置该 csc 元素的 target。在该例中,我将创建一个 .dll 文件,因此我将 target 设置为 library。接下来,我必须设置 csc 元素的 output,它是将要创建 .dll 文件的位置。最后,我需要设置 debug 属性,它确定了是否在调试中编译该项目。因为我在前面创建了一个用于存储该值的属性,所以我可以使用下面的字符串来访问该属性的值:${debug}。Csc 元素还包含一些子元素。我需要创建两个元素:references 元素将告诉 NAnt 需要为该项目引用哪些程序集,sources 元素告诉 NAnt 要在生成过程中包含哪些文件。在该示例中,我引用了 NUnit.Framework.dll 程序集并包含了 HashtableTest.cs 文件。图 8 中显示了完整的生成文件。(您通常还要创建一个干净的 target,用于删除生成的文件,但为了简洁起见,我已经将其省略。)

要生成该文件,我需要转到我的项目的根目录(生成文件位于此处),然后从该位置执行 nant.exe。如果生成成功,您可以在该应用程序的 bin 目录中找到 .dll 和 .pdb 文件。尽管使用 NAnt 肯定不像在 Visual Studio 中单击 Build 那样简单,但它仍然是一种非常强大的工具,可用于开发按自动计划运行的生成过程。NAnt 还包括一些有用的功能,例如能够运行单元测试或者复制附加文件(这些功能没有受到当前 Visual Studio 生成过程的支持)。

NAnt 是一个开放源代码项目,并且可以从 http://nant.sourceforge.net 下载。

返回页首
转换工具
我已经将两个独立的工具合在一起放在标题“转换工具”下面。这两个工具都非常简单,但又可能极为有用。第一个工具是 ASP.NET 版本转换器,它可用于转换 ASP.NET(虚拟目录在它下面运行)的版本。第二个工具是 Visual Studio Converter,它可用于将项目文件从 Visual Studio .NET 2002 转换到 Visual Studio .NET 2003。

当 IIS 处理请求时,它会查看正在请求的文件的扩展名,然后基于该 Web 站点或虚拟目录的扩展名映射,将请求委派给 ISAPI 扩展或者自己处理该请求。这正是 ASP.NET 的工作方式;将为所有 ASP.NET 扩展名注册扩展名映射,并将这些扩展名映射导向 aspnet_isapi.dll。这种工作方式是完美无缺的,除非您安装了 ASP.NET 1.1 — 它会将扩展名映射升级到新版本的 aspnet_isapi.dll。当在 ASP.NET 1.0 上生成的应用程序试图用 1.1 版运行时,这会导致错误。要解决该问题,可以将所有扩展名映射重新转换到 1.0 版的 aspnet_isapi.dll,但是由于有 18 种扩展名映射,所以手动完成这一工作将很枯燥。这正是 ASP.NET 版本转换器可以发挥作用的时候。使用这一小型实用工具,可以转换任何单个 ASP.NET 应用程序所使用的 .NET 框架的版本。


按此在新窗口打开图片
图 9 ASP.NET 版本转换器


图 9 显示了实际运行的 ASP.NET 版本转换器。它的使用方法非常简单,只须选择相应的应用程序,然后选择您希望该应用程序使用的 .NET 框架版本。该工具随后将使用 aspnet_regiis.exe 命令行工具将该应用程序转换到所选版本的框架。随着将来版本的 ASP.NET 和 .NET 框架的发布,该工具将变得更为有用。

ASP.NET 版本转换器由 Denis Bauer 编写,并且可以从 http://www.denisbauer.com/NETTools/ASPNETVersionSwitcher.aspx 下载。

Visual Studio .NET 项目转换器(参见图 10)非常类似于 ASP.NET 版本转换器,区别在于它用于转换 Visual Studio 项目文件的版本。尽管在 .NET 框架的 1.0 版和 1.1 版之间只有很小的差异,但一旦将项目文件从 Visual Studio .NET 2002 转换到 Visual Studio .NET 2003,将无法再把它转换回去。虽然这在大多数时候可能不会成为问题(因为在 .NET 框架 1.0 版和 1.1 版之间几乎没有什么破坏性的更改),但在某些时刻您可能需要将项目转换回去。该转换器可以将任何解决方案或项目文件从 Visual Studio 7.1 (Visual Studio .NET 2003) 转换到 Visual Studio 7.0 (Visual Studio .NET 2002),并在必要时进行反向转换。


按此在新窗口打开图片
图 10 Visual Studio .NET 项目转换器


Visual Studio .NET 项目转换器由 Dacris Software 编写。该工具可以从 http://www.codeproject.com/macro/vsconvert.asp 下载。

返回页首
小结
本文采用走马观花的方式介绍了上述工具,但我已经试图起码向您提供足够的信息以激起您的好奇心。我相信本文已经让您在某种程度上领悟了几个免费工具,您可以立即开始使用这些工具来编写更好的项目。同时,我还要敦促您确保自己拥有所有其他可以获得的合适工具,无论是最新版本的 Visual Studio、功能强大的计算机还是免费的实用工具。拥有合适的工具将使一切变得大不相同。

James Avery 是一位使用 .NET 和其他 Microsoft 技术的顾问。他已经撰写了许多书籍和文章,他的最新著作是《ASP.NET Setup and Configuration Pocket Reference》(Microsoft Press, 2003)。您可以通过 javery@infozerk.com 向他发送电子邮件,并且在 http://www.dotavery.com/blog 阅读他的网络日记。
posted @ 2007-05-18 23:11 colys 阅读(621) | 评论 (5)编辑 收藏

2007年5月15日 #

面向对象的设计模式是经验的总结,MVC思想是原先用于构建用户界面的。这篇文章主要论述了如何在新的Web应用领域中使用设计模式和MVC架构。文章首先介绍了设计模式的概念和特点,以及MVC架构的设计思想,并分析了MVC架构中包含的几种主要的模式。然后根据Web应用系统的特点,就如何应用模式和MVC架构提出了一些设计思路。

1. 引言
1.1 设计模式

面向对象技术的出现和应用大大提高了软件的重用性和软件的质量。面向对象的编程也比以往的各种编程模式要简单和高效,但是面向对象的设计方法要比以往的设计方法要复杂和有技巧得多,一个良好的设计应该既具有对问题的针对性,也充分考虑到对将来问题和需求有足够的通用性。在过去的十几年中,人们在对面向对象技术的研究探索和实际应用中针对某些问题创造了一些良好的解决方案,即所谓的面向对象的设计模式。面向对象技术的目的之一就是提高软件的重用性,而对设计模式、设计方案的重用则从更深的层次上体现了重用的意义和本质。
人们对设计模式有很多定义,其中被引用的最多是Christopher Alexander的设计模式的定义:每一个设计模式是一个三方的规则,它表达了一个上下文环境(Context),一个问题和一个解决方案。设计模式一般有如下几个基本要素:模式名称,问题,目的,解决方案,效果,样例代码和相关设计模式。
设计模式的分类有好几种,可以根据其目的分为创建型(Creational),结构型(Structural)和行为型(Behavioral)三种。创建型模式主要是用来创建对象,结构型模式主要是处理类或对象的组合,行为型模式则主要用来描述对类或对象怎样交互和怎样分配职责。也可以根据范围将设计模式分为类模式和对象模式,类模式处理类和子类之间的关系,这些关系通过继承建立,在编译时刻就被确定下来,是属于静态的。对象模式是处理对象间的关系,这些关系在运行时刻变化,更具动态性。
模式的特点:是通过经验获取的,以某种结构化的格式书写下来,避免了遇到相同的问题重头设计,存在于不同的抽象层,在不断完善的,是可重用的人工产物,使设计和最好的练习交互,以被组合起来解决更大的问题。

1.2 MVC架构
MVC最初是在Smalltalk-80中被用来构建用户界面的。M代表模型Model, V代表视图 View, C代表 控制器Controller。
MVC的目的是增加代码的重用率,减少数据表达,数据描述和应用操作的耦合度。 同时也使得软件可维护性,可修复性,可扩展性,灵活性以及封装性大大提高。
单用户的应用通常是以事件驱动的用户界面为组织结构的。开发人员用一个界面工具画了一个用户接口界面,然后编写代码根据用户输入去执行相应的动作,许多交互式的开发环境鼓励这么做,因为它强调先有界面然后再有功能。一些软件设计模式策略是这样的,然后经常将固定后的代码融入最后的系统当中。导致的结果就是,程序组织围绕用户界面元素和用户在那些界面元素上的动作,数据的存储,应用的功能以及用来显示的代码都杂乱无章的缠绕在一起。在单用户的系统里代码结构是可以这样的,因为系统需求不会频繁变化。但是对一个大的系统如大型Web系统,或电子商务系统来说就不太适用了。
通过把数据模式从各种可以被存取和控制的数据中分离出来可以改善分布式系统的设计。MVC设计模式由三部分组成。模型是应用对象,没有用户界面。视图表示它在屏幕上的显示,代表流向用户的数据。控制器定义用户界面对用户输入的响应方式,负责把用户的动作转成针对Model的操作。Model 通过更新View的数据来反映数据的变化。
三者关系如图:


对MVC关系图的理解

图2 MVC的分工与协作

2. MVC中的设计模式
一个以MVC为架构的系统包含了很多的设计模式,但是与MVC最为密切相关的是下面三种模式:Observer, Composite和Strategy。
2.1 Observer模式
MVC通过使用定购/通知的方式分离了Model和View。View要保证自己显示能正确地反映出Model的内容和状态。一旦Model的内容发生变化,必须有一个机制来使得Model能够通知相关的View,使得相关的View可以在适当的时机刷新数据。这个设计还可以解决更一般的问题,将对象分离,使得一个对象的改变能够影响到另一些对象,而这个对象并不知道那些被影响的对象的细节。这就是被描述为Observer的设计模式。
模式类型:Observer模式是对象型模式,同时它也是行为型模式。
模式目的:定义对象间的一对多的依赖关系,当一个对象的值或状态发生改变时,所有与它有依赖关系的对象都得到通知并自动更新。某一数据可能有多种显示方式,并且可能同时以不同的方式显示(如图2)。当通过某一种方式改变了数据,那么其他的显示都应该能立即知道数据的改变和做相应的调整。
模式结构:

图 3. Observer模式的结构图

效果:
1. 抽象耦合。目标对象只知道它有一些观察者,每个观察者都符合抽象的Observer类的简单接口,并不知道它们具体属于哪个类。这样使得目标和观察者之间的耦合最小且抽象。
2. 支持广播通信。目标发送通知不用指定观察者,如何处理通知由观察者决定。
3. 可能的意外更新。要处理好更新逻辑,避免错误更新。

2.2 Composite模式
MVC的一个重要特征就是View可以嵌套。嵌套的组合视图可用于任何视图可用的地方,而且可以管理嵌套视图。这种思想反映出将组合的视图与其组件平等对待的设计。这种设计思想在面向对象领域内被描述成为Composite的设计模式。
模式类型:Composite模式是对象型模式,同时它也是结构型模式。
模式目的:将对象组合成树形结构以表示"部分-整体"层次结构。Composite使组合对象的使用和单个对象的使用具有一致性。
模式结构:

图4. Composite模式的结构图
效果:
1. 定义了包含简单对象和组合对象的类层次结构。简单对象可以被组合到复杂对象中,而组合的对象可以再被组合。这样客户端代码中用到简单对象的地方都可以使用组合对象。
2. 简化客户端代码。客户端不用知道某对象是简单对象还是组合对象,可以以一致的方式使用这些对象。
3. 更容易增加新类型的组件。新的组件可以方便地加入已有组合对象中不用改变客户端代码。

2.3 Strategy模式
MVC的另一重要特征是可以在不改变View的情况下改变View对用户输入的响应方式。这对一个经常需要变更响应逻辑的系统来说是非常重要的。MVC把响应逻辑封装在Controller中。有一个Controller的类层次结构,可以方便地对原有Controller做适当改变,创建新的Controller。View使用Controller子类的实例来实现一个特定的响应策略。要实现不同的响应策略,只要用不同种类的Controller实例替换即可。还可以在运行时刻通过改变View的Controller来改变View对用户输入的响应策略。这种View-Controller的关系是被描述为Strategy的设计模式的一个例子。
模式类型:Strategy模式是对象型模式,同时它也是行为型模式。
模式目的:定义一系列的算法,并且把它们封装起来,使它们可以互相替换,使得算法可以独立于使用它的客户端而变化。
模式结构:

图5. Strategy模式的结构图

效果:
1. Strategy类层次为Context定义了可重用的相关算法或行为。
2. 替代继承的方法。如果直接继承Context,给以不同的行为,会将行为加到Context中,从而将算法的实现与Context混合起来,使Context难以理解,维护和扩展,而且不能动态地改变算法。将算法封装在独立的Strategy类,可以使得算法独立于Context改变,容易切换扩展。
3. 可以提供相同行为的不同实现。
4. 客户端必须了解Strategy之间有何不同。
5. Context和Strategy之间的通信开销。
6. 增加了对象的数目。

3. MVC在 Web系统中的应用
现在的一些基于Web的分布式系统如B2B电子商务系统,就适合采用MVC架构。
通过分析,从高层次的角度可以将一个应用的对象分为三类。一类就是负责显示的对象,一类对象包含商业规则和数据,还有一类就是接收请求,控制商业对象去完成请求。这些应用的显示是经常需要变换的,如网页的风格,色调,还有需要显示的内容,内容的显示方式等。而商业规则和数据是相对要稳定的。因此,表示显示的对象View经常需要变化的,表示商业规则和数据的对象Model要相对稳定,而表示控制的Controller则最稳定。
通常当系统发布后,View对象是由美工,HTML/JSP设计人员或者系统管理员来负责管理的。Controller对象由应用开发人员开发实施,商业规则对象和商业数据对象则由开发人员,领域专家和数据库管理员共同完成的。显示逻辑在Web层或客户端控制,可以是Servlet 或JSP,动态地生成Html。一般来说采用JSP要比采用Servlet要好。JSP更好地将代码与Html部分分开,有利于页面设计人员和代码开发人员的分离,提高效率。同时JSP可以完成所有Servlet完成的功能,实际上JSP最终也转换成一个Servlet。与控制有关的对象存在于系统的每一个层次,协调跨层动作。包含商业规则和数据的对象存在于EJB层(以EJB为中心的模式)或Web层(以Web为中心的模式)。

3.1 View在Web系统中的应用
View代表系统的显示,它完全存在于Web层。一般由JSP, Java Bean和Custom Tag组成。JSP可以动态生成网页内容,Custom Tag 更方便了使用Java Bean,而且它可以封装显示逻辑,更有利于于模块化和重用。一些设计良好的Custom Tag可以在多个JSP甚至可以在不同的系统里重复使用。Java Bean用来控制JSP和Model对象。JSP通过Java Bean 来读取Model对象中的数据,Model和Controller对象则负责对Java Bean的数据更新。一般来说,可以先要设计出所有可能出现的屏幕,即用户使用系统时可以看到的所有内容。然后根据这些内容,找出公共部分,静态部分和动态变化部分。可以考虑使用模板方法,把公用的内容单独生成JSP,需要变化的也各自生成Html或JSP, 由一个模板JSP, 把这些不同部分动态地引入(include方法)。还有一个要考虑的问题就是屏幕的选择问题,当处理完用户请求,模板被自动调用来显示,这个显示一定要知道用户关心的屏幕是有哪些部分组成。所以可以考虑把所有屏幕的定义放在一个集中的文件里,如一个java文件或文本文件。由于考虑到屏幕定义文件将来的变更可能性,最好使用文本文件如一个XML文件,这样将来更改不用重新编译。可以根据用户输入的URL和参数可以映射到某一个结果屏幕,当然有可能还要根据动作的执行结果选择不同的结果屏幕内容。所以需要一个请求与资源的匹配文件(XML),如果一个URL请求有几种不同结果,则要在该文件中指明是否需要流控制(一种controller对象)以及不同流向的对应屏幕。

3.2 Model在Web系统中的应用

Model对象代表了商业规则和商业数据,存在于EJB层和Web层。在J2EE的规范中,系统有些数据需要存储于数据库中,如用户的账号信息(account model),公司的数据(company model)等,也有一些不需要记录在数据库里的,如某用户浏览的当前产品目录(catalog model),他的购物内容(shopping cart model)等。这些model数据存在于哪一层要根据它们的生命周期和范围来决定。在Web层有HttpSession和ServletContext及Java Bean对象来存储数据,在EJB层则有EJB来存储数据和逻辑。Web层的Java Bean的model对象存储了EJB层model对象的数据的拷贝。因为EJB层有很多不同的model对象,所以Web层可以通过一个ModelManager来控制EJB层的各model对象,在ModelManger中可以封装使用后台model对象的方法。
在EJB层把所有的数据和规则都模式化为EJB也是不恰当的。如可以把存取数据库的对象模式化为DAO对象。DAO中可以封装与具体数据库的交互细节,如可以读写不同的表,多个数据库,甚至多种数据库。如定单的model对象可以是一个OrderDAO, 它可能要同时处理Order表,OrderStatus表和OrderItemLines表。
还有可以考虑使用Value对象。一个Value 对象可以封装远程对象,因为每一个读远程对象的属性都可能是一个远程过程调用,都会耗费网络资源。可以在EJB的远程对象中使用Value对象. 在远程对象中一次性得到Value对象来得到所有属性的值。

3.3 Controller在Web系统中的应用
Controller对象协调Model与View,把用户请求翻译成系统识别的事件。在Web层,一般有一个MainServlet(或Main.jsp),接收所有请求,它可以调用屏幕流管理器(ScreenFlowManger)决定下一个屏幕。一般还有一个请求处理器RequestProcessor,包含所有请求都需要做的处理逻辑,如把请求翻译成系统事件(RequestToEvent)。请求处理器通常还包含一个代理对象ClientControlWebImpl,它是EJB层的逻辑处理的在Web层的代理。在EJB层,有一个ClientController提供Web 层对EJB层的只读访问。还有一个StateMachine用来建立和删除ejb,处理Web层送来的事件。
Controller还有一个重要的功能就是同步View和Model的数据。在ModelManger中包含一个ModelUpdateManger,它把系统事件转换为一个Model的集合,即所有需要同步的Model,然后通知Listeners去做同步操作。

4. 结束语
近年来随着互联网技术的发展和新的商业模式的出现,必然会出现大量基于Web的应用系统。对于如何设计这些系统的体系结构,也逐渐有了一些统一的认识,最主要的是的就是其体系结构要合理,开放。需求永远会比技术和设计思想发展快,要使将来系统的升级所付出的代价最小,研究软件系统的体系结构还是非常很用和有必要的。

参考文献
[1] 设计模式,作者Erich Gamma 等,ISBN 7-111-07575-7, 机械工业出版社 2000.9
[2] Core J2EE Patterns, 作者Deepak Alurm 等, ISBN 0-13-064884-1, Sun Microsystems Inc, 2001年
[3] Designing Enterprise Applications with the J2EETM Platform, 作者Nicholas Kassem 等, Sun Microsystems, Inc. 2000年

posted @ 2007-05-15 09:12 colys 阅读(404) | 评论 (0)编辑 收藏

2007年4月22日 #

题目:

有十个开关等间距排成一线,每个开关对应其上方的一盏灯(十盏灯也排成一线)。每按动一下开关,可以使对应的灯改变状态(原来亮着的将熄灭,原来熄灭的将被点亮)。
但是,由于开关之间的距离很小,每次按动开关时,相邻的一个开关也将被按动。例如:按动第5个开关,则实际上第4、5、6个开关都被按动。而按动靠边的第1个开关时,第1、2个开关都被按动。并且,无法只按动最靠边的一个开关。
现在给出十盏灯的初始的状态和目标状态,要求计算:从初始状态改变到目标状态所需要的最少操作次数。
函数接口:
int MinChange(const int Start[],const int End[]);
其中:Start表示了初始状态,End表示了目标状态。表示状态的数组(Start和End)中,若某元素为0表示对应的灯亮着,否则表示对应的灯没有亮。调用函数时保证Start和End数组长度均为10,并保证有解。

看了很多人的解法都是用循环遍历来判断是否达到最后要求,但是如果和线形代数结合的话,就有一种很快速的解法。

约定:以下所用的‘+’号都是‘异或’的运算。
先简化一下,假设有四个灯,初始状态s0~s3,目标状态是e0~e3,转换一次状态就是和1进行异或运算一次,所以状态转移矩阵为:
(s0,s1,s2,s3)+k0*(1,1,0,0)+k1*(1,1,1,0)+k2*(0,1,1,1)+k3*(0,0,1,1)=(e0,e1,e2,e3);
其中k(n)表示第n个开关所翻动的次数。并且,注意异或运算中a+b+b=a,所以,某个开关翻动偶数次的效果相当于没有翻动,翻动奇数次的效果相当于翻动一次;又由于异或运算满足交换律,所以翻动的顺序没有影响。综上每个开关翻动的次数只有1次或0次就足够了。

设m(n)=s(n)+e(n),注意异或运算中的'-'也就是'+',所以解线性方程组:
k0+k1      =m1;
k0+k1+k2   =m2;
   k1+k2+k3=m3;
      k2+k3=m4;
假设解存在,就可以算出通解(k0,k1,k2,k3),再统计出通解中1的个数,就是所需要翻动的次数了。并且还可以知道哪些开关需要拨动,比如算出解是(1,0,1,0)就是第0和2个开关需要拨动一次。

因此针对本题目的10个灯泡,本人已算出这10元线性方程组的通解:
k0=m0+m2+m3+m5+m6+m8+m9;
k1=m2+m3+m5+m6+m8+m9;
k2=m0+m1;
k3=m3+m0+m1+m5+m6+m8+m9;
k4=m5+m6+m8+m9;
k5=m4+m3+m0+m1;
k6=m6+m4+m3+m0+m1+m8+m9;
k7=m8+m9;
k8=m7+m6+m4+m3+m0+m1;
k9=m9+m7+m6+m4+m3+m0+m1;

和上面一样,m(n)为开始状态与目标状态的每位异或。至于是否存在解,本人已将次系数矩阵化简为对角矩阵,可以看到系数矩阵的秩(Rank)与未知数的个数相等,所以无论是任何的输入和输出变换都能找到唯一解。

本人程序如下:
int MinChange(const int Start[],const int End[]){
    int m[10];
    int k[10];
    int res=0;
    int i,j,n;
    for(i=0;i<10;i++){
            m[i]=Start[i]^End[i];  /* m[]=Start[] XOR End[] */
        }
    /* calculate roots */
    k[0]=m[0]^m[2]^m[3]^m[5]^m[6]^m[8]^m[9];
    k[1]=m[2]^m[3]^m[5]^m[6]^m[8]^m[9];
    k[2]=m[0]^m[1];
    k[3]=m[3]^m[0]^m[1]^m[5]^m[6]^m[8]^m[9];
    k[4]=m[5]^m[6]^m[8]^m[9];
    k[5]=m[4]^m[3]^m[0]^m[1];
    k[6]=m[6]^m[4]^m[3]^m[0]^m[1]^m[8]^m[9];
    k[7]=m[8]^m[9];
    k[8]=m[7]^m[6]^m[4]^m[3]^m[0]^m[1];
    k[9]=m[9]^m[7]^m[6]^m[4]^m[3]^m[0]^m[1];
    /* count for switch times */
    for(j=0;j<10;j++){
        if(k[j]) res++;
        }
    /* display k(n); */
    for(n=0;n<10;n++) printf("%d,",k[n]);
    return res;
}

测试主程序:
main(){
    int A[10]={1,1,1,0,0,1,0,1,1,0};
    int B[10]={0,0,1,1,0,0,1,1,1,1};
    int C;
    C=MinChange(A,B);
    printf("**%d**",C);
}
显示结果为:
1,0,0,0,1,1,1,1,0,1,**6**
就是如果要把状态A转为状态B,需要把第0,4,5,6,7,9号开关翻动一次,共6次。
测试验证结果正确:)

当然,此做法也有一个缺点,就是当灯的个数改变时,就要重新设定线形方程组的特解形式。


posted @ 2007-04-22 10:02 colys 阅读(339) | 评论 (1)编辑 收藏



l 初始化
² 当页面被提交请求第一个方法永远是构造函数。您可以在构造函数里面初始一些自定义属性或对象,不过这时候因 为页面还没有被完全初始化所以多少会有些限制。特别地,您需要使用HttpContext对象。当前可以使用的对象包括QueryString, Form以及Cookies集合,还有Cache对象。注意:在构造函数里是不允许使用Session的。

² 下一个将执行的方法是AddParsedSubObject方法,这个方法将添加所有独立的控件并把页面组成一个控件集合树,这个方 法经常被一些高级的页面模板解决方案(Page Template Solutions)重写以便添加页面内容到页面模板(Page Template)中一些特殊的控件中。这个方法递归应用到所有的页面控件及相应的的每个子控件,所有的控件都是在这个方法中开始最早的初始化。

² 页面类中下一个将执行的方法是DeterminePostBackMode。这个方法允许您修改IsPostBack的值及相关的事件。如果您 需要从数据库中加载ViewState这个方法将特别有用,因为ViewState只有在IsPostBack为真的情况下才会进行恢复。返回空将会导致 强制执行非回传,返回Request.Form则强制执行一个回传。除非在特殊情况下,否则并不建议去操作这个,因为这个还会影响其他的事件。

² 下一个将要执行的方法是OnInit方法,一般这是第一个真正被使用的方法。这个方法触发时,所有页面定义中的控件执行初始化,这意味着所有在 页面中定义的值应用到相应的控件上。不过,ViewState和传回的值还不会应用到控件上,因此,任何被代码或用户改变的值还没有被恢复到控件上。这个 方法通常是最好的创建、重创建动态控件的好地方。
l 恢复及加载
² 下一个方法, LoadPageStateFromPersistenceMedium只会在页面被回传的时候才会被执行。如果因为使用Session或自定义存储方 式,您修改了后面将要提到的影响ViewState保存方式的方法SavePageStateToPersistenceMedium,则这个方法需要被 重写。默认的实现中ViewState是一种Base64格式编码,并且被保存在页面的隐藏域中,您可以使用这篇文章中提及的方法修改ViewState 按以上两种方式保存。注意:这个方法并没有真正加载ViewState到页面或页面控件中。

² 当得到ViewState后,下一个方法LoadViewSate,将以递归的方式恢复ViewState到页面及各个页面控件或子控件中。这 个方法执行后,每个控件都将恢复到上一次的状态,但是用户提交的数据还没有应用到控件上,因为他们不是ViewState的一部分。这个方法主要用于恢复 您在其他事件中动态生成的控件的值,他们的值是您手动保存在ViewSate中,并且现在已经失效。

² 下一个方法是ProcessPostData,这个方法也同样是回传的时候才会被执行,并且不允许被重写,这个是页面基类的私有方法。这个方法 通过匹配控件的名称恢复相应的用户提交的控件的值,到这一步意味着整个页面都已经被完全恢复了。唯一要记住的是所有动态控件的创建必须在这个方法之前。这 个方法也是记录后面的改变事件的方法。

² 下一个方法是OnLoad方法,通常这是用得最多的方法,因为这个方法是页面生存期第一个恢复了所有值的地方。大多数代码根据判断 IsPostBack来决定是否重新设置控件状态。您也可以在这个方法中调用Validate并且检查IsValid的值。也可以在这个方法中创建动态控 件,并且该控件的所有的方法都会被执行以追上当前页面的状态包括ViewSate,不过不包括回传的值。
l 事件处理
² 下一个方法还是 ProcessPostData,实际上就是前一个方法的另一次调用,它仍然是只在回传的时候执行并且由于是私有方法不可以被重写。如果您是第一次看页面 的运行轨迹也许会觉得这个方法有些多余。但实际上这个方法是必要的因为在OnLoad中创建的动态控件也需要他们回传的值。任何在这以后创建的控件将可以 得到他们的ViewState,但是不能再得到他们的回传的值,并且不会触发任何值改变事件(Change Event)。

² 下一个方法,RaiseChangedEvents,也是只在回传页面中执行,并且也因为是基类的私有方法所有不能被继承。在整个页面生存期 中,是在这儿根据之前的ProcessPostData记录的控件的值和提交的值是否不同来触发值改变事件。您也许需要调用Validate或者检查 IsValid的值。这里并没有特别的说明多个值改变事件的执行先后顺序。

² 下一个方法,RaisePostBackEvent,同样是因为是基类的私有方法不能被继承,同样也是只在回传页面中执行。除非使用了 AutoPostBack,不然这是实际提交表单事件执行的地方,特别是按钮或者其实使用javascript提交表单等。如果还没有被手动调用过并且使 用了验证控件,那么Validate会被调用。注意IE中有个BUG有时会允许提交但却不触发任何事件。

² 下一个方法是OnPreRender,一般这是在客户端展现页面之前改变页面及其控件的最后一次机会。您也可以在这个方法里面创建动态控件,并 且所有的方法都会被执行以追上当前页面的状态包括ViewSate,但是私有方法将不会被执行,这意味着不会有回传的值并且不会有事件触发。由于IE中的 BUG,这是一个没有事件赶上PostBack的好地方。
l 保存及显示
² 下一个方法是SaveViewState,不论是否是回传页 面,均会递归的执行以保存页面及其所有控件的ViewState。ViewState基本上保存所有与定义在aspx中的原始值不同的值,不管是被代码还 是用户所改变。注意控件值是根据他们在页面的控件树中的位置来保存的,所以如果动态控件后来加到了错误的位置将会导致混乱。

² 下一个方法是SavePageStateToPersistenceMedium真正的保存页面的ViewSate。这个方法随同 LoadPageStateFromPersistenceMediumg 一起被重写以便保存ViewState到Session或其它自定义数据,而不是用隐藏域。这对于低带宽的用户来说是很有帮助的。并且对于移动设备来说, Session是默认设置。下面这篇文章描述了使用以上两种方式保存ViewState的具体细节。注意在Asp.net中有个Bug:Asp.net要 求必须提交__viewstate字段,即使是空的。

² 下一个方法是Render方法,该方法递归的创建并发送相应控件的html给浏览器。这个方法被一些页面模板方案重写以添加一些通用的页面头与 脚而不使用服务器控件,他们总是有一些额外的东西。注意这儿的修改只能使用纯HTML,因为控件在这儿已经被生成了。您可以用 StringBuilder,StringWriter,HtmlTextWriter捕获相应的HTML输出。

² 最后的方法是OnUnload,这个方法会调用相应的Dispose方法。这个方法提供机会以便清空该页面中使用的非托管资源,如关闭打开的文 件句柄,以前打开的数据库连接等。注意这个方法是在页面已经发送到客户端以后执行的,所以它只有影响服务器对象,并且它不会显示在页面的显示轨迹中。这就 是页面的生存期,对于每一次请求都是这么运行的。
l 作者简介(略)

表1:页面事件总结


方法回传控件


ConstructorAlwaysAll
AddParsedSubObjectAlwaysAll
DeterminePostBackModeAlwaysPage
OnInitAlwaysAll


LoadPageStateFromPersistenceMediumPostBackPage
LoadViewStatePostBackAll
ProcessPostData1PostBackPage
OnLoadAlwaysAll


ProcessPostData2PostBackPage
RaiseChangedEventsPostBackPage
RaisePostBackEventPostBackPage
OnPreRenderAlwaysAll


SaveViewStateAlwaysAll
SavePageStateToPersistenceMediumAlwaysPage
RenderAlwaysAll
OnUnloadAlwaysAll

posted @ 2007-04-22 09:27 colys 阅读(466) | 评论 (1)编辑 收藏

2007年3月19日 #

1.神要是公然去跟人作对,那是任何人都难以对付的。 (《荷马史诗》)

2.生存还是毁灭,这是一个值得思考的问题。 (《哈姆霄特》)

3.善良人在追求中纵然迷惘,却终将意识到有一条正途。(《浮士德》)

4.认识自己的无知是认识世界的最可靠的方法。 (《随笔集》)

5.你以为我贫穷、相貌平平就没有感情吗?我向你发誓,如果上帝赋予我财富和美貌,我会让你无法离开我,就像我现在无法离开你一样。虽然上帝没有这么做,可我们在精神上依然是平等的。(《简?爱》)

6.大人都学坏了,上帝正考验他们呢,你还没有受考验,你应当照着孩子的想法生活。 (《童年》)

7,你越没有心肝,就越高升得快,你毫不留情地打击人家,人家就怕你。只能把男男女女当作驿马,把它们骑得筋疲力尽,到了站上丢下来,这样你就能达到欲望的最高峰。 (《高老头》)

8.我只想证明一件事,就是,那时魔鬼引诱我,后来又告诉我,说我没有权利走那条路,因为我不过是个虱子,和所有其余的人一样。 (《罪与罚》)

9.你瞧,桑丘?潘沙朋友,那边出现了三十多个大得出奇的巨人。 (《堂?吉诃德》)

10.我并不愿意你受的苦比我受的还大,希斯克利夫。我只愿我们永远不分离:如果我有一句话使你今后难过,想想我在地下也感到一样的难过,看在我自己的份上,饶恕我吧! (《呼啸山庄》)

11.幸福的家庭是相同的,不幸的家庭各有各的不同。 (《安娜?卡列尼娜》)

12.唉,奴隶般的意大利,你哀痛之逆旅,你这暴风雨中没有舵手的孤舟,你不再是各省的主妇,而是妓院! (《神曲》)

13.将感情埋藏得太深有时是件坏事。如果一个女人掩饰了对自己所爱的男子的感情,她也许就失去了得到他的机会。 (《傲慢与偏见》)

14.钟声又鸣响了……一声又一声,静谧而安详,即使在女人做新娘的那个好月份里,钟声里也总带有秋天的味道。 (《喧嚣与骚动》)

15.一个人并不是生来要被打败的,你尽可以把他消灭掉,可就是打不败他。 (《老人与海》)

   16.当然,行是行的,这固然很好,可是千万别闹出什么乱子来啊。 (《套中人》)

   17.面包!面包!我们要面包! (《萌芽》)

   18.我从没有爱过这世界,它对我也一样。 (《拜伦诗选》)

19.  爱情应该给人一种自由感,而不是囚禁感。 (《儿子与情人》)

   20.暴风雨将要在那一天,甚至把一些槲树吹倒,一些教堂的高塔要倒塌,一些宫殿也将要动摇! (《海涅诗选》)

   21.自己的行为最惹人耻笑的人,却永远是最先去说别人坏话的人。 (《伪君子》)

   22.这时一种精神上的感慨油然而生,认为人生是由啜泣、抽噎和微笑组成的,而抽噎占了其中绝大部分。(《欧?亨利短篇小说选》)

   23.历史喜爱英勇豪迈的事迹,同时也谴责这种事迹所造成的后果。 (《神秘岛》)

   24.整个下半天,人都听凭羊脂球去思索。不过本来一直称呼她作“夫人”,现在却简单地称呼她作“小姐”了,谁也不很知道这是为着什么,仿 佛她从前在评价当中爬到了某种地位,现在呢,人都想把她从那种地位拉下一级似的,使她明白自己的地位是尚叩摹?(《莫泊桑短篇小说选》)

25.如果冬天来了,春天还会远吗?  (《雪莱诗选》)

   26.我明白了,我已经找到了存在的答案,我恶心的答案,我整个生命的答案。其实,我所理解的一切事物都可以归结为荒诞这个根本的东西。(《恶心》)

   27.世界上有这样一些幸福的人,他们把自己的痛苦化作他人的幸福,他们挥泪埋葬了自己在尘世间的希望,它却变成了种子,长出鲜花和香膏,为孤苦伶仃的苦命人医治创伤。(《汤姆叔叔的小屋》)

   28.当格里高?萨姆莎从烦躁不安的梦中醒来时,发现他在床上变成了一个巨大的跳蚤。(《变形记》)

   29.当现实折过来严丝合缝地贴在我们长期的梦想上时,它盖住了梦想,与它混为一体,如同两个同样的图形重叠起来合而为一一样。(《追忆似水年华》)

   30.人与人之间,最可痛心的事莫过于在你认为理应获得善意和友谊的地方,却遭受了烦扰和损害。(《巨人传》)

   31.现在我说的您要特别注意听:在别人心中存在的人,就是这个人的灵魂。这才是您本身,才是您的意识在一生当中赖以呼吸、营养以至陶醉的东西,这也就是您的灵魂、您的不朽和存在于别人身上的您的生命。(《日瓦戈医生》)

   32.美德犹如名香,经燃烧或压榨而其香愈烈,盖幸运最能显露恶德而厄运最能显露美德。(《培根论说文集》)

   33.亲爱的艾妮斯,我出国,为了爱你,我留在国外,为了爱你,我回国,也是为了爱你!(《大卫?科波菲尔》)

   34.强迫经常使热恋的人更加铁心,而从来不能叫他们回心转意。(《阴谋与爱情》)

35.在各种事物的常理中,爱情是无法改变和阻挡的,因为就本性而言,爱只会自行消亡,任何计谋都难以使它逆转。(《十日谈》)

   36.只要你是天鹅蛋,就是生在养鸡场里也没有什么关系。(《安徒生童话》)

   37.就投机钻营来说,世故的价值永远是无可比拟的。(《死魂灵》)

   38. 谁都可能出个错儿,你在一件事情上越琢磨得多就越容易出错。(《好兵帅克历险记》)

   39.我们经历着生活中突然降临的一切,毫无防备,就像演员进入初排。如果生活中的第一次彩排便是生活本身,那生活有什么价值呢?(《生命中不能承受之轻》)

   40.他发现了人类行为的一********自己还不知道——那就是,为了要使一个大人或小孩极想干某样事情,只需要设法把那件事情弄得不易到手就行了。(《汤姆?索亚历险记》)

   41.对有信仰的人,死是永生之门。(《失乐园》)

   42.有一个传说,说的是有那么一只鸟儿,它一生只唱一次,那歌声比世上所有一切生灵的歌声都更加优美动听。(《荆棘鸟》)

   43.离开一辈子后,他又回到了自己出生的那片土地上。从小到大,他一直是那个地方的目击者。(《尤利西斯》)

   44.同上帝保持联系是一码事,他们都赞同这一点,但让上帝一天二十四小时都待在身边就是另一码事了。(《第二十二条军规》)

   45.在甜蜜的梦乡里,人人都是平等的,但是当太阳升起,生存的斗争重新开始时,人与人之间又是多么的不平等。(《总统先生》)

   46.开发人类智力的矿藏是少不了要由患难来促成的。(《基度山伯爵》)

   47.离你越近的地方,路途越远;最简单的音调,需要最艰苦的练习。(《泰戈尔诗选》)

   48.悲伤使人格外敏锐。(《约翰?克里斯朵夫》

   49.我在女人跟前经常失败,就是由于我太爱她们了。(《忏悔录》)
posted @ 2007-03-19 20:23 colys| 编辑 收藏