• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            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 閱讀(1511) | 評論 (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 閱讀(2155) | 評論 (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 閱讀(1456) | 評論 (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 閱讀(361) | 評論 (0)編輯 收藏

            2007年8月24日 #

            http://www.cnblogs.com/hardrock/archive/2006/08/18/480668.html
            posted @ 2007-08-24 10:29 colys 閱讀(460) | 評論 (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 閱讀(1374) | 評論 (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 閱讀(800) | 評論 (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 閱讀(1770) | 評論 (15)編輯 收藏

            2007年5月27日 #

              在運行vs2003安裝時老提示我是要更新還是刪除,我都還沒裝怎么會有這個項呢!后來仔細看了看這個提示是屬于我裝的一個極點輸入法的! 卸載掉后安裝正常!

              事情可不是都那么順,安裝后運行一切正常,欣喜.....花了我好多時間!
            但不過多久,在下一次開機后,它罷工了! 提示DI.DLL找不到! 多次運行還是如此! 想都不想,重裝! 又是一陣等待...
            再運行,oh,shit "找不到.dll 文件"

              無語..難道這就是microsoft的東東嗎? 為什么以前安裝和使用就沒遇到這問題嗎? 突然一個思想在我腦海里浮現,既然安裝和輸入法會有關,但運行會不會也如此!但極點五筆不是被我卸載掉了嗎? 難道是五筆加加的問題?(我裝有兩個五筆輸入法~~) 于是乎卸載掉五筆加加!再裝吧...等待...

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

            posted @ 2007-05-27 23:50 colys 閱讀(536) | 評論 (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 閱讀(644) | 評論 (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 閱讀(481) | 評論 (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 閱讀(360) | 評論 (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 閱讀(543) | 評論 (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| 編輯 收藏

            亚洲国产精品一区二区三区久久| 欧美亚洲国产精品久久| 久久99这里只有精品国产| 精品一区二区久久久久久久网站| 伊人久久大香线焦AV综合影院| 中文字幕久久亚洲一区| 久久久精品久久久久久| 久久久久成人精品无码 | 91久久福利国产成人精品| 日韩精品无码久久久久久| 青草国产精品久久久久久| 精品人妻伦九区久久AAA片69| 久久天天躁狠狠躁夜夜avapp| 久久人妻无码中文字幕| 中文字幕乱码人妻无码久久| 久久久国产精华液| 色欲av伊人久久大香线蕉影院| 国内精品久久久久影院薰衣草 | 99久久精品免费看国产一区二区三区| 久久久受www免费人成| 精品久久久久成人码免费动漫| 奇米影视7777久久精品人人爽| 亚洲精品蜜桃久久久久久| 久久精品免费观看| 久久久久人妻一区精品| 亚洲精品乱码久久久久久中文字幕 | 亚洲国产成人久久综合一| 久久国产美女免费观看精品 | 久久综合狠狠综合久久激情 | yellow中文字幕久久网| 天堂无码久久综合东京热| 久久久久亚洲精品无码蜜桃| 亚洲嫩草影院久久精品| 成人久久免费网站| 精品国产热久久久福利| 午夜不卡久久精品无码免费| 久久精品国产亚洲一区二区三区| 亚洲综合精品香蕉久久网| 国内精品久久久久久久久| 亚洲精品乱码久久久久久中文字幕| 亚洲国产精品久久久久网站 |