最新文章

顯示具有 重劍無鋒 標籤的文章。 顯示所有文章
顯示具有 重劍無鋒 標籤的文章。 顯示所有文章

所以基本還是很重要的

5月 11, 2010
2010.05.11 (二)
 
3/31 這幾天面試有感這一篇中,有提到我在面試時相當重視基本的資料結構和演算法。

有些朋友回答我說,其實像他們都不是很重視。
有些朋友也說:不會這些還是可以做程設啊!



image
(再次聲名圖片和主題無關...我只是想要在職場類的文章都加上OL圖而已)
 

程式設計的兩個觀點 中,作者王建興先生也有提到類似的觀點。

文章前面2 /3 乍看似乎是說基礎的不必要~~
但剛好相反,在後半時,作者話鋒一轉,帶出了基礎的重要性。

....為什麼即使已經有許多現成的演算法及資料結構,甚至是其他用途的程式庫,程式員還是必須修習像演算法及資料結構這樣子的課程?

演算法基本是一門探討以電腦程式解決問題的學問,時間複雜度和空間複雜度是貫穿演算法這門學問的主要支柱。

時間複雜度和空間複雜度所代表的是什麼?正是代表解決問題在時間上以及空間上所需付出的代價。

我們學習演算法,除了學習常見的演算問題分類,以及如何解決這些演算問題之外, 更重要的是要學習解決問題的方法,以及培養解決問題時的成本意識。


即使大多數的應用程式開發者毋需憂心於新型演算法的設計問題,但是對於常見的演算法諸如排序、搜尋等,最好具備一定的認識, 在撰寫程式時才能知道究竟有那些工具可供取用。

而且,更重要的是,在撰寫程式碼時,隨時都應該對演算的成本保持警覺,尤其對於每一個高階的抽象操作, 都應該確切的了解其演算的成本及代價。

高階抽象包裝有時就像糖衣,它包覆的究竟對你來說是不是毒藥,必須要時時刻刻小心。
倘若在撰寫程式時,僅考慮架構上的特性,缺乏成本意識、忽略了演算特性,那麼還是很容易在無意中寫下效能低落的程式碼,無法設計出新的演算法不是真正的問題所在,這才是真正的問題所在!...


程設人員的優與劣,可相差至百倍之譜。
不是只有將程式碼拼湊起來,就可以交差。

抓的到老鼠的就是好貓。
但是,太肥或反應太慢的貓,確定抓的到老鼠嗎?

這些基本的東西,也是我在面試時,一定會問的。
順便也可以看看本科系的應試者,當初學習的情況。
也希望剛出社會,想走這一行的新鮮人,多花些時間在這些你所謂 "已經不需要" 的東西上面。

軟體開發經典圖的說明

5月 30, 2009
之前有貼過,軟體開發的經典說明圖
後來在ptt上看到有人在討論它的意義,覺得很棒,所以整理出來。
當然這張圖的解釋是因人而異囉,你也可以有自己的解釋呢 ^^

縮圖上的文字看不清楚,建議點進去看大圖呦 ^^


從左上圖一,到右下圖十。
參考ptt上的討論,再加上我的一些認知來一一進行解釋。 ^^"

圖一:
客戶描述他的需求, 但是客戶往往連他自己也弄不清楚到底真正要的是什麼。
用它自己的辭彙,連輪胎鞦韆都說不出來,只講的出鞦韆。
而且還功能重複,一片板子就夠的東西硬要作三片........

圖二:
PM (專案經理) 至少案子接多了,知道點狀況,板子用一片就夠。
但因為脫離實作太久了,只用腦袋憑空想像出架構

只知道有樹、有鞦韆,鞦韆綁在樹枝上。
至於鞦韆實不實用就不管了 XD

結果就搞出這種看似ok,實際上一 run 就完蛋的系統.....

圖三:
系統分析師一看:靠! 這東西根本不能run嘛!
系統分析最常碰到的盲點 - 頭痛醫頭,腳痛醫腳
流程走不下去了,再旁邊多加兩個子流程補起來就好......

圖四:
程設師說:客戶要有樹,有繩子,有鞦韆,我都寫出來給你了,還缺什麼嗎?
再補一刀:而且 "Unit Test 都有過喔 = ="

圖五:
企管顧問:你這鞦韆是要用來坐的,但是既然要坐,
沙發肯定比板子更能發揮貴公司的競爭優勢。

板子不用拆,再導入一張沙發吧。

(另一種解釋是,顧問可以把你家的破鞦韆唬爛成
金光閃閃瑞氣千條,樣樣符合國際標準的高級貨...... )

圖六:
文件? (無言...)
專案文件完成度,跟國王的新衣差不多,有跟沒有其實是一樣的.. 囧

圖七:
User 端的環境,本來就只能裝一條繩子,而且只能綁輪胎。
安裝人員拿了金光閃閃的鞦韆系統去User端,
能裝起來的大概只剩條繩子.....
整合測試跟上線測試就等著被幹爆吧


圖八:
跟客戶收費,收的錢都可以蓋一座雲宵飛車了!

圖九:
支援? 砍掉重練比較快.
通常都是叫個倒楣鬼,抱著那堆國王新衣文件,自己慢慢研究。
還有個根能出來,算是不錯的了.......

圖十:
搞到最後,其實客戶要的是一個懸吊在樹枝上的輪胎。

圖片來源



程式設計之道

5月 19, 2009
原作是冼鏡光,曾載於PC微電腦傳真雜誌上,以前我看到後就非常喜歡這篇。
總覺得每次看就有一些不同的領悟 XD
看到這篇編排的很好,就借過來一用了。
原址在東邪島 - 程式設計之道


----------------------------------------------------------



第一部 寂靜虛無篇



大師如是說:“學會從程式抓蟲子之後,就可以畢業了。”


1.1 節

寂靜虛無中有奧秘,不動不靜,乃程式之源,吾無以名之,故稱之為程式設計之道。

若道至大,則作業系統至大;若作業系統至大,編譯程式亦然;若編譯程式至大,則應用程式亦復如是,是故使用人大悅,世有和諧存焉。


1.2 節

程式設計之道無遠弗屆,雖晨曦微風而返。

道生機器語言,機器語言生組譯程式。組譯程式生編譯程式,於是萬餘語言存焉。

各語言有其目的,均表達軟體之陰陽;其在道中亦各得其所。

但若能避免,就不要用COBOL 寫程式。


1.3 節

太初有道,道生時空,故時空乃程式設計之陰陽。

程式員不悟道則時空永不敷使用,悟道者恒有充份時空完成目標。


1.4 節

上智程式員聞道而行之,中智程式員聞道而求之,下智程式員聞道而笑之。

若無笑聲則無道矣。至高之聲難以聽聞。

前進就是後退之路;大智總是晚成;每一個完美的程式仍有BUG。

道在所有知識之外。


第二部 古之大師篇

大師如是說:“三日不寫程式則生命無趣。”


2.1 節

古程式員神秘而深奧,無以度量其思維,僅能描述其表象。

像狐狸涉水般地小心;像戰場老兵般地警覺;像未經琢磨的木頭般地璞拙;像洞中深潭地不透明。誰能指出他們心靈中的秘密?答案全在道中。


2.2 節

大師Turing曾經夢到他是一部電腦,醒後道:

“不知是我Turing作夢變成機器,還是一部機器作夢變成我Turing。”

一家大電腦公司的程式員參加軟體會議後,向他的經理報告說:“你知道其他電腦公司有什麼程式員嗎? 他們不修邊幅,頭髮長而邋遢,衣服既舊且皺,他們破壞了氣氛,而且我簡報時老是製造噪音。”

經理說:“我根本就不應該派你參加會議,這些程式員超然物外,他們把生命看成無稽,意外的結合。他們往來而無藩籬,為他們的程式而活,為什們他們一定要受社會積習的約束?他們生活在道中。”


2.3 節

生手問大師:“有一個程式員從不設計,測試程式,寫作文獻,但了解他的人都認為他是世間最好的程式員。為什麼?”

大師曰:“這個程式員已充份悟道,他超越了設計的需要;系統垮了不會生氣,而無條件接受這個世界。他超越了文獻的需要,他不再計較是否有人看他的程式。他也超越了測試的需要,他的每一個程式都圓滿無缺,清澈,優雅,目的自明。是的,他已悟道,登堂入室。”


第三部 設計篇

大師說:“到測試程式時再回頭修改設計就太遲了。”


3.1 節

曾經有人在參觀電腦展每天進門時都向警衛說:“我是的妙賊,偷東西的技巧已臻化境,先告訴你,我絕不會放過這次展覽。”

這段話刺激到警衛,因為展覽場有好幾百萬元價值的儀器,所以老是盯這他,不過卻只看到這個人一個攤位接著一個攤位看,哼著小曲而已。

這個人出門的時侯,警衛把他帶到一旁搜身,但卻找不到什麼。

第二天這個人又來了,而且教訓警衛說:“昨天我收獲不錯,不過今天會更佳。”所以警衛就更加注意他了,但是仍然沒有結果。

最後一天警衛終於忍不住好奇心,問那個人:“賊大師,我給您弄得寢食難安,您是否以教我,究竟偷了些什麼?”

這個人笑笑,說:“我偷的是概念。”


3.2 節

從前有一位大師專寫沒有結構化的程式,一個生手模仿他,也開始寫沒有結構化的程式。當這位生手要求大師評量進展時,大師卻批評他寫作沒有結構化的程式。

大師說:“對大師適用的不一定適合生手,在能超越結構化之前,必須先悟道。”


3.3 節

某長官問程式員:“設計會計系統與作業系統,那一個比較簡單?”

程式員說:“作業系統。”

長官發出不相信的驚呼:“很顯然的,會計系統不如作業系統複雜”,他說。” 不!”程式員回答,“在設計會計系統時,程式員是各種不同主意的人之間的橋樑,這些主意不外乎: 系統要如何作業? 報表型式如何? 要如何迎合稅法?...等等。反過來,作業系統卻不受外界表象的限制;在設計作業系統時,程式員尋求人與機器間最純的和諧,這就是為什麼作業系統容易設 計。”

長官點頭微笑稱是:“但是那一個容易偵錯?”

程式員沒有回答。


3.4 節

經理去見大師,並且告訴他一套新應用程式文件的需求規格,問道:“如果我給你五個程式員,要多久才能設計好這個系統?”

大師很快回答:“一年。”

“但是我們需要馬上用這個系統! 如果我給你十個程式員,那要多久?”經理說。

大師皺眉說:“這要兩年。”

如果我給你一百個程式員呢?”

大師聳聳肩:“這個系統根本作不出來了。”


第四部 寫作篇

大師如是說:“寫作良好的程式本身自成天堂,寫得差的程式本身就是地獄。”


4.1 節

程式要輕靈,副程式像一串珍珠。程式的精神與意圖應始終如一,不多不少;沒有多餘的迴圈,也沒有額外的變數,既不缺少結構,也不過份笨重。

程式應該追隨“最低驚訝定律”,這是什麼?

簡單得很,使用人對程式的反應是驚訝的機會要愈低愈好。

程式不管再複雜,應該以一個整體來作用;他應該用內部邏輯,而不是外在的表象來指導作業。

如果程式不滿足這些要求,就會雜亂而易生混淆,唯一的補救就是重新寫過。


4.2 節

生手問大師:“我有一個程式,有時侯作得很好,有時侯卻不行;我一直遵行程式設計的規律,但是卻把我弄得很困擾,其理安在?”

大師答曰:“因為不悟道才會如此,只有笨蛋才會期望他的同儕有合理的行為,而你卻對人類生產的機器有所期望?!計算機只模擬了決定論,只有道才十全十美。程式設計的準則還是暫時性的,只有道才會進入永恒。所以,你在開竅前要先思索道。”

“但我要如何才能知道已經開竅了呢?”生手問。

大師回答:“從此以後,你的程式都能正確執行。”


4.3 節

大師對弟子說:“不論軟體之為大為小,道在所有軟體中。”

“桌上型計算機有道嗎?”弟子問。

“有!”大師答。

“電動玩具程式中有道嗎?”弟子續問。

“也有!”大師說。

“那個人電腦的DOS 中有道嗎?”

大師咳一下,輕輕挪動了位置,“下課”,他說。


4.4 節

皇太子的程式員正在寫作軟體,指尖在鍵盤上飛舞,程式順暢無誤的編譯完成,執行起來像陣微風輕拂而完美的結束。

“了不起!”,太子嘆曰:“你的技巧無懈可擊。”

“技巧?”程式員從終端機上轉過頭說,“我所信從的是道,道超越任何技巧!我開始學寫程式時,在我眼前所見是混成一片的程式;三年後,不再見到這一大 片程式了,我學會使用副程式;現在,眼前一片空靈,什麼都沒有了,所有東西都進入無型式的一片靜寂;所有感覺都不必作用。我的精神可以依直覺而不必依任何 計劃行事,換言之,我的程式自己寫作自己。當然,有時會有困難的問題;我看著他們到來,我降低自已的速度,靜靜的看,改一列程式之後困難就會煙消雲散;我 再重新靜靜坐著欣賞工作的歡樂。我閉上雙眼一會兒,然後關機。”

皇太子說:“我的所有程式員都那麼聰明睿智嗎?”


第五部 維護篇

大師如是說:“雖然程式只有三列,但總有一天需要維護。”


5.1 節

常用的門不必上油。

急流不會淤塞。

聲音與思想不能在真空中傳遞。

不用的軟體會生鏽。

這就是至大的奧秘。


5.2 節

經理問程式員究竟要多久才能把手上的程式寫完。“明天",程式員很快的回答。

經理說:“我想你不太踏實;真的要多久?”

程式員想了一會兒:“我希望在程式中加上一些東西,這至少要兩週。”程式員終於說 。

“時間還是短了一些",經理堅持說:“如果你能簡單的告訴我什麼時後能寫完我才會滿意。”

程式員同意這一點。

幾年後經理退休了,在歡送餐會上發現那個程式員伏在終端機上睡著了,因為他寫程式寫了整夜。


5.3 節

一個生手被分派去寫一個單純的財務軟體。

這個生手狂熱地工做了幾天,但是當大師看他的成品時,卻發現這個程式中包含一個螢光幕編修程式,一組一般性的繪圖程式,一個人工智慧界面,但卻沒有什麼與財務方面有關。

大師就問他,這個生手卻變得很激動:“不要那麼沒耐心,”他說,“我最終會把財務部份加上去。”


5.4 節

好農夫會忽視他種的穀子嗎?

好老師會忽略他最差的學生嗎?

好父親會容許他的孩子挨餓嗎?

好程式員會拒絕維護自己的程式嗎?


第六部 管理篇

大師如是說:“程式員要多,經理要少,生產力就會增加。”


6.1 節

經理有開不完的會的話,程式員就會寫電玩;主計部門想到利潤,發展經費就會被刪減;高級科學家談到藍藍青天,那麼青天一定會有浮雲飛過。

當然,這不是程式設計之道。

當經理許下承諾,程式員就不理會電玩;當主計部門有長程規劃,就會回復和諧與秩序;當高級科學家處理手上的問題,問題很快就會解決。

這才是程式設計之道。


6.2 節

為什麼程式員沒有生產力? 因為他們的時間都花在開會上頭。

為什麼程式員難以駕御? 因為管理階層干預太多。

為什麼程式員一個接一個辭職? 因為他們精力耗光了。

在不良管理下工作,程式員不會覺得他的工作有價值。


6.3 節

某個經理快被炒魷魚了,但是他底下的一個程式員寫了一個叫好又叫座的程式;當然,這位經理因而保住了飯碗。

經理打算給這位程式員一點獎勵,但他拒絕接受,並且說:“因為我覺得這是個有趣的概念,才會寫這個程式,所以我不希望有獎勵。”

經理聽了之後說:“這個程式員雖然職位不高,但卻充份了解做為一個職員的責任,讓我們把他升成崇高的管理顧問吧!”

在告訴程式員時,他再度拒絕,說:“我之存在是因為可以寫程式,如果升了我,那除了浪費每一個人的時間外而成不了事。我可以走了嗎? 我還得寫程式。”


6.4 節

經理告訴程式員們說:“下面是你們的工作時間: 早上九點來上班,下午五點鐘下班。”所有程式員都很生氣,有幾個馬上辭職。

於是經理說:“好吧! 這樣好了,只要能夠如期完工,工作時間由你們自定。”程式員現在滿意了,每天中午開始工作,直到第二天早上。


第七部 公司智慧篇

大師如是說:“你可以對主管示範一個程式,但無法讓他通曉電腦。”


7.1 節

生手問大師:“遙遠東方有一個叫"公司總部" 的偉大樹狀結構,上面滿滿地標上了些副總裁,會計長等的圖案。它發出大量的備忘錄,每張上面都寫了"收文!" "發文!"沒有人知道是什麼意義。每年都會把新的名字加到新的分枝上,但似乎全都徒勞無功。為什麼這樣一個不自然的組織還能繼續存在?”

大師回答說:“你已經體認到這個龐大的結構,而被它不合理的目的困擾。不過你能不從它無休止的迴旋而得到樂趣嗎? 能夠不欣賞深藏在枝葉底端毫無困難的程式設計嗎? 為什麼要被他的無用而困擾呢。”


7.2 節

東方海上有大魚曰鯤,鯤能變成雙翼遮天的大鵬。當大鵬飛越陸地時帶來一道公司總部的訊息,這道訊息正好掉在一群程式員中央,然後大鵬折起雙翼乘風而歸。

生手程式員瞪眼望著大鵬,因為他們不認得;中智程式員憂大鵬的來臨,因為他們害怕它帶來的訊息;只有大師才能繼續坐在終端機前工作,因為他不知大鵬的來去。


7.3 節

象牙塔的魔術師帶著他的最新發明去見大師,他推了一個大黑盒子走進大師的辦公室,大師正在靜靜的等著。

“這是一套整合性,分散式,一般用途的工作站",魔術師如是說,“還有一套專屬的作業系統,第六代語言,多項最先進的使用人界面,再加上人體工學的設計;這花了我的助手們好幾百人年才造出來的,不是很了不起嗎?”

大師抬了下眼珠子,“的確了不起。”大師說。

魔術師繼續說:“公司總部已經下令每個人都要用這台工作站做發展新軟體的基石,您同意嗎?”

“當然。”大師答道:“我馬上會把它放到資訊中心去。”於是魔術師高高興興的回到象牙塔去。

幾天後,一個生手在大師的辦公室裡團團轉,說:“我找不到新程式的報表,您知道會在那兒嗎?”

“當然",大師答道,“報表就堆在資訊中心裡頭的基石上!”




7.4 節

大師可以毫無憂慮的從這個程式轉入另一個程式,管理上的改變傷不到他;縱使計劃中止了,也不會被炒魷魚。為什麼? 因為他充滿了道。


第八部 硬體與軟體篇

大師如是說:“沒有風,草不會動,沒有軟體,硬體就是廢物。”


8.1 節

生手問大師:“我知道一家電腦公司比其他的大得多,高高在上就像巨人之比侏儒;它的任一部都可以單獨成為一個企業。為什麼會這樣?”

大師回答:“你為什麼問這個笨問題? 這家公司就是因為它大才會這麼大。如果它只知道硬體,沒有人會買它;如果只生產軟體,沒有人會用它;如果只維護系統,人家會把它看成修理員;但是因為他把 所有的合在一起,人們就把它當神一樣看待了。它根本無需競爭,因為贏來不費吹灰之力。”


8.2 節

大師有一天經過一個生手旁邊,發現生手迷上一台手掌型的電玩,“對不起",大師說,“我可以看看它嗎?”

生手停下來,並且把這台機器交給大師。大師說:“我看到這台機器玩起來有三個層次:初級,中級,高級;不過這種機器通常都有另一個層次的說法,使機器贏不了人類,而人類也勝不了機器。”

“啊! 大師",生手說:“這個奇妙的開關在那裡?”

大師把機器摔到地上,用腳把它踏爛。

突然地,生手開竅了。


8.3 節

從前有一位微電腦的程式員對一位來拜訪他的大型電腦程式員說:“你看,在我這兒多好! 我有我自己的作業系統與案儲存設備,我不必與任何人共用任何電腦資源;軟體本身自給自足,而且容易使用。為什麼你不辭掉目前的工作來加入我們?”

於是大型電腦的程式員就對他的朋友解釋:“大型電腦就像古之聖哲般的穩穩座落在資訊中心中央,磁碟一個接一個蔚為奇觀,軟體像鑽石般地有多種面目,像古森林般的濃密茂盛。各個程式像一片急流般地湧入系統,而這就是我在那兒工作的樂趣 。”

聽了這段話之後,微電腦程式員靜默無聲;但是這兩個人卻結為好友,至死不渝。


8.4 節

Hardware 與 Software 走在路上,Software 說:“你是陰我是陽,如果我們能一條心,一定會成大名賺大錢。”所以,他們就聯合在一起而想征服世界。

走了一段路之後,碰到Firmware,穿得破破爛爛,拿著根柺杖,並且對他們說:“道在陰陽之外,寂靜不動如古井之不生波瀾;道不求名,故無人知曉其存在;道不逐利,因它圓滿無缺。道超乎時空之外。”

Hardware 和 Software 聽了之後倍感慚愧而打道回家。


第九部 尾聲

大師如是說:“這是下課的時候了!”



軟體開發的經典說明圖

11月 21, 2008
這是在解說軟體開發時常用的圖,蠻有趣的。
昨天剛好看到同事有,就和她要來囉 !




Oracle Security Alert #54 & #57

11月 10, 2008
ID: 1643 - [Oracle] Oracle Database Servers 'CREATE DATABASE LINK' 緩衝區溢位 : 1521

我用 google 查第54號alert,連到大陸官方站的重要補丁更新和安全情報,再連到support站台

再查得metalink應該是:
2974483 (要先登入)
這樣就可以直接下載 patch 檔了。

[轉貼][教學]使用Visual Studio 2005製作應用程式的安裝檔

10月 30, 2008
轉貼自:http://sedc.pixnet.net/blog/post/14882266

寫應用程式時,如果引用了許多週邊的函式庫或dll檔案,在將程式的成品搬移至其他電腦執行時,是不是常發生東漏一個圖檔、西漏一個dll的情況呢?對於使用Visual Studio來寫程式的設計者,可以用它內建的「佈署專案」來製作整個程式的安裝檔,將你專案的程式及所需的檔案包裝在一個msi檔中,如此一來只要設定好佈署專案的內容,就不必擔心每次要帶到其他電腦上執行時會有缺漏了。

以下便配合圖片來介紹如何使用佈署專案,使用的版本是Visual Studio 2005 Service Pack1

我們先拿一個範例專案MyProgram,來當做成品的應用程式,在這裡它是一個以C#寫成的Windows Form應用程式,輸出檔為MyProgram.exe。

在這個專案中,我們參考了.NET的Managed DirectX,如上圖的Microsoft.DirectX、Microsoft.DirectX.Direct3D、 Microsoft.DirectX.Direct3DX三項,另外還參考了一個自己找到的MgdWM4Wrapper,它是一個名為 MgdWM4Wrapper.dll的dll檔案。

接著在最上面的方案(也叫MyProgram)接右鍵,選擇加入->新增專案




選擇左邊的其他專案類型,再選擇右邊的安裝專案,接著在下方的名稱輸入自己要的專案名稱,它也會是最後產生出來的msi檔的預設名稱。

專案建立完成後,會自動開啟出該專案的設定檔案系統的頁面:




這個頁面的介面基本上就跟檔案總管的型式是類似的,左邊是資料夾,右邊是資料夾的內容。在佈署專案的檔案系統中,有三個資料夾的內容要設定,分別是「使用 者的桌面」、「使用者的程式功能表」--分別可以設定要在使用者的桌面和程式集功能表中加入哪些檔案(通常是捷徑),以及「應用程式資料夾」--存放應用 程式所需檔案的地方,通常就是使用者電腦的「C:\Program Files」資料夾。在這裡我們先從「應用程式資料夾」一項開始設定,因為上二項的捷徑會需要對應至它其中的檔案。

在左邊的應用程式資料夾上按右鍵,移到加入之上,會有四類的東西可以選擇:



如果你希望在程式的資料夾中,再多建幾個資料夾以分類檔案,可以選擇加入資料夾。在這裡我們先選擇最重要的專案輸出



在這個視窗中,最上面的專案下拉式列表可以讓你選擇同在一個方案中的專案,以本例而言僅有MyProgram專案。中間的視窗可以讓你選擇該專案中的哪些部份要加入至佈署中,可以配合Ctrl或Shift做複數選取,通常選擇主要輸出即可。 再下面的組態這是選擇該專案是要以什麼樣的建構版本加入至佈署(Debug或Release),預設是作用中,即跟從該專案現在的設定。

按下確定後,我們可以發現除了MyProgram的主要輸出(即MyProgram.exe檔)外,其他額外的參考組件也被加入至應用程式資料夾中了,同時在「方案總管」中,SetupProgram專案的「偵測到的相依性」也列出了該四項組件。



除了專案輸出之外,如果應用程式有其他需要的檔案,也可以用加入->檔案的方式,加入至應用程式資料夾中。為了開發上的方便,最好是讓開發專案的資料夾及檔案配置,能與佈署專案中安排的配置一致,才不會開發時改一套,佈署時又要改一套。

接下來我們設定一下應用程式資料夾的屬性,在「使用者的應用程式」的屬性視窗中,有二項需要注意的屬性:


佈署專案的每個資料夾都會有AlwaysCreate屬性需要設定,它表示「即使該資料夾是空的,是否仍要建立」,預設值為False。通常是不會需要設定成True,但若你的專案有需要事先建立空白的資料夾時,可以把該資料夾的屬性設定為True。另一個屬性是DefaultLocation,它代表了在使用者的電腦中的位置,預設值是 [ProgramFilesFolder] [Manufacturer]\[ProductName] ,我們以常用的軟體Adobe Reader的路徑為例:

C:\Program Files\Adobe\Reader 8.0

[ProgramFilesFolder] -> C:\ProgramFiles
[Manufacturer] -> Adobe
[ProductName] -> Reader 8.0

如果要照這個預設值來安裝應用程式的話,後續的佈署專案屬性設定中可以設定Manufacturer及ProductName的值。


應用程式資料夾的設定完成後,我們就可以來設定要在使用者的程式集和桌面上擺入哪些捷徑。對於每一個在應用程式資料夾中,你想對其設置捷徑的檔案(通常是應用程式的執行檔),在它上面按右鍵,選擇建立xxxx的捷徑,接著將其重新命名為你希望使用者看到的名稱:



命名後,將其拖曳至左方的「使用者的桌面」資料夾。對於「使用者的程式功能表」資料夾也如法炮製(捷徑要重製作一個),不過建議先在「使用者的程式功能表」下建立好公司名稱與程式名稱的資料夾,再將捷徑放進去;否則捷徑便會擺在使用者的程式集中的最外層。



捷徑都設置完畢後,我們便可以來對佈署專案做最後的屬性設定(其實這部份要最先做也可以啦)


這裡比較需要記得設定的屬性有:
Author -> 應用程式的作者
Manufacturer -> 應用程式的開發公司
ProductName -> 應用程式的名稱 如上面所提過,這二個屬性可以決定程式安裝的路徑
RemovePreviousVersions -> 當發現使用者的電腦中有較舊版本的同一應用程式時,是否要先移除舊版本
Title -> 安裝程式的標題
Version -> 指定安裝程式的版本,可以配合RemovePreviousVersions屬性來決定與舊版本程式的配合。

除了屬性視窗中列出的屬性,其實佈署專案還有一個屬性頁面要設定,在方案總管中,於佈署專案的名稱上按右鍵,選擇屬性,會開啟下面這個視窗:



組態同樣可以設定佈署專案是要以Debug還是Release模式建置;輸出檔名稱可以設定msi檔的名稱;套件檔案可以選擇要將應用程式的檔案包含在msi檔、或是另外用一個cab檔包著、或是鬆散的檔案。若選擇前二者,則還可以設定壓縮是要以速度還是大小為優先做考量。最後按下必要條件進入最後的設定頁面:



在這個視窗中,Visual Studio 2005會先幫你挑選好它偵測到的應用程式所需的必要元件,如本例中為.NET Framework 2.0。如果你擔心使用者電腦的Windows Installer可能版本不夠新或是損壞,可以再勾選Windows Installer 2.0或3.1版。最下面的三種選項,是設定安裝程式會在使用者的電腦上如何安裝這些必要元件,最保險的方法是從應用程式的相同位置下載必要條件,這會將這些必要元件的可轉散發安裝檔一起放在安裝程式中,缺點自然是整個安裝程式的大小會變得龐大,優點則是可以確保即使目標電腦沒有網路也能安裝這些必要元件。

最後一步,在方案總管中,於佈署專案的名稱上按右鍵,選擇建置,就會開始產生安裝程式囉!視你所選擇的建置模式而異,可以到佈署專案的輸出資料夾下去看看有哪些檔案,以本例來看,檔案是放在Visual Studio 2005的Projects資料夾中,\
MyProgram\SetupMyProgram\Debug 資料夾下:



不論剛剛的專案屬性選擇為何,都會有一個setup.exe檔案,通常它就是整個安裝程式的起點,會在安裝應用程式前檢查使用者的電腦是否有安裝應用程式的必要元件,如果沒有,則會開始下載並安裝必要元件(以上圖來看,因設定了從應用程式的相同位置下載必要條件, 故會從一同產生的dotnetfix資料夾來安裝)。若不需要考慮必要元件,且當初「套件檔案」是選擇含在安裝檔中,則其實可以只拿msi檔去使用者的電 腦安裝。除了安裝,Windows Installer其實連移除的工作也都幫我們設定好了,使用者之後也可以從控制台中的「新增/移除程式」來移除你的應用程式,實在是相當方便。

有關佈署專案的教學就到這邊,其實還有一些小細節設定可以調整,就讓各位高手們去自己試試啦。

VS 2005 C++/CLI 的 config 檔~~~

10月 17, 2008
平常我們會將資料庫連線字串等資訊,存放在 web.config 或是 app.config 等組態檔中。

但這次在用 C++/CLI 開發AP時,才發現不管怎麼用,就是無法取得 app.config 中的資料~~~~

原本的 ConfigurationManager 都會取得 null!

後來才知道,原來C++/CLI根本不認識啥 app.config..... = =

所以我們必須在專案的屬性頁中,做 "建置後事件" 的設定,讓 VS2005 幫我們 copy 一個 config 檔到執行目錄下:

















在DB(用到的專案)的屬性頁,選建置事件,再選建置後事件。輸入:

copy app.config "$(TargetPath).config"

之後就可以像之前用C#一樣的方式來取得 config 中的值了!








輸出畫面中,可以看到VS2005進行建置後事件,並copy了那個app.config。

[轉貼] C++編程人員容易犯的10個C#錯誤

6月 11, 2007

我又看見一個獸從海中上來、有十角七頭、在十角上戴著十個冠冕、七頭上有褻瀆的名號。
我所看見的獸、形狀像豹、腳像熊的腳、口像獅子的口.那龍將自己的能力、座位、和大權柄、都給了他...

~聖經 啓示錄第十三

中心應該有部分同仁和我一樣,是從C++轉到C#的吧?剛好看到這篇文章,也順便把自己這段時間的一些心得加上,和大家討論。
雖說原文的標題是十個"錯誤",但其實是太誇張了,不如說是十個注意事項...

由於對岸的許多用語和我們不同,所以我儘可能將之翻成台灣的用語,或是加上英文名詞。因為常看侯捷大哥的書,所以台灣用語會取自他的譯法。其他可能會混淆的部分,我會在另外再加註囉!我的心得用綠色字呦。

~3rd Jason

--------------------------------------------------------------------

簡體原文網頁

我們知道,C#的語法與C++非常相似,實現從C++向C#的轉變,其困難不在於語言本身,而在於熟悉.NET的可管理環境和對.NET Framework 的理解。

儘管C#與C++在語法上的變化是很小的,幾乎不會對我們有什麼影響,但有些變化卻足以使一些粗心的C++編程人員時刻銘記在心。在本篇文章中我們將討論C++編程人員最容易犯的十個錯誤。

錯誤1:沒有明確的結束函式

幾乎可以完全肯定地說,對於大多數C++編程人員而言,C#與C++最大的不同之處就在於垃圾收集(GC)。這也意味著編程人員再也無需擔心記憶體洩露和確保刪除所有沒有用的指標。但我們再也無法精確地控制殺死無用的物件這個過程。事實上,在C#中沒有明確的destructor。

如果使用非可管理性資源,在不使用這些資源後,必須明確地釋放它。對資源的隱性控制是由Finalize函式(也被稱為finalizer)提供的,當物件被銷毀時,它就會被GC程序呼叫收回物件所佔用的資源。

finalizer應該只釋放被銷毀物件佔用的非可管理性資源,而不應牽涉到其他物件。如果在程序中只使用了可管理性資源,那就無需也不應當執行 Finalize函式,只有在非可管理性資源的處理中才會用到Finalize函式。由於finalizer需要佔用一定的資源,因此應當只在需要它的函式中執行finalizer。

直接呼叫一個物件的Finalize函式是絕對不允許的(除非是在子類別別的Finalize中呼叫父類別別的Finalize。),GC程序會自動地呼叫Finalize。

從語法上看,C#中的destructor與C++非常相似,但其實它們是完全不同的。C#中的destructor只是定義Finalize函式的捷徑。

Jason註:其實C#解構式在編譯後,會變成:

c# 原始碼
  1. protected override void Finalize()
  2. {
  3. try
  4. {
  5. ...
  6. }
  7. finally
  8. {
  9. base.Finalize();
  10. }
  11. }

由於 Finalize() 的被呼叫時機無法預測,所以它只能當做釋放資源的第二道防線。
主要還是使用 Dispose。

錯誤2:Finalize 和 Dispose 使用誰?

從上面的論述中我們已經很清楚,直接呼叫finalizer是不允許的,它只能被GC程序呼叫。如果希望儘快地釋放一些不再使用的數量有限的非可管理性資源(如handle),則應該使用IDisposable界面,這一界面有個Dispose函式,它能夠幫你完成這個任務。Dispose是無需等待 Finalize被呼叫而能夠釋放非可管理性資源的函式。

如果已經使用了Dispose函式,則應當阻止GC程序再對相應的物件執行Finalize函式。為此,需要呼叫靜態函式 GC.SuppressFinalize,並將相應物件的指標傳遞給它作為參數,Finalize函式就能呼叫Dispose函式了。據此,我們能夠得到如下的程式碼:

c# 原始碼
  1. publicvoidDispose()

  2. {

  3. //完成清理操作

  4. //通知GC不要再呼叫Finalize函式

  5. GC.SuppressFinalize(this);

  6. }

  7. publicoverridevoidFinalize()

  8. {

  9. Dispose();

  10. base.Finalize();

  11. }

對於有些物件,可能呼叫Close函式就更合適,可以通過建立一個private屬性的 Dispose函式和public屬性的Close函式,並讓Close呼叫Dispose來實現對某些物件呼叫Close函式。

由於不能確定一定會呼叫Dispose,而且finalizer的執行也是不確定的(我們無法控制GC會在何時運行),C#提供了一個using 語法來保證Dispose函式會在儘可能早的時間被呼叫。一般的函式是定義使用哪個物件,然後用括號為這些物件指定一個活動的範圍,當遇到最內層的括號時, Dispose函式就會被自動呼叫,對該物件進行處理。

c# 原始碼
  1. using System.Drawing;

  2. class Tester

  3. {

  4. public static void Main()

  5. {

  6. using(FonttheFont = new Font("Arial",10.0f))

  7. {

  8. //使用theFont物件

  9. }//編譯器將呼叫Dispose處理theFont物件

  10. Font anotherFont = newFont("Courier",12.0f);

  11. using( anotherFont)

  12. {

  13. //使用anotherFont物件

  14. }//編譯器將呼叫Dispose處理anotherFont物件

  15. }

  16. }

在本例的第一部分中,Font物件是在Using陳述中產生的。當Using語句結束時,系統就會呼叫Dispose,對Font物件進行處理。在本例的第二部分,Font物件是在Using語句外部產生的,在決定使用它時,再將它放在Using語句內,當Using語句結束時,系統就會呼叫 Dispose。

Using語句還能防止其他意外的發生,保證系統一定會呼叫Dispose。

Jason註:和錯誤1相同,編譯器會在編譯時把using區間用 try / finally 包起來。
有提供Close函式的物件,如資料庫連線、檔案...等,可以從外部直接呼叫 Close 來釋放資源。


錯誤3:C#中的值型別變數(Value Type Variable)和參考型別變數(Reference Type Variable)是有區別的

與C++一樣,C#也是一種 strong-type (嚴格型別)語言。C#中的資料型別被分為了二大類:C#語言本身所固有的資料型別和使用者定義資料型別,這一點也與C++相似。

此外,C#語言還把變數分為值型別和參考型別。除非是被包含在一個參考型別中,否則值類別型變數的值會保留在堆疊(stack)中,這一點與C++中的"變數"非常相似。參考型別的變數也是堆疊的一種,它的值是堆積(heap)中物件的地址,與C++中的"指標"非常地相似。值型別變數變數的值被直接傳遞給函式,參考型別變數在被作為參數傳遞給函式時,傳遞的是索引。

類別和界面可以建立參考型別,但需要指出的是,結構 (struct) 是C#的一種內建資料型別,同時也是一種值型別變數。

Jason: 也就是C#中 class 和 struct 的區別,比起C++來說,又多了這一樣


錯誤4:注意隱式(implicit)的資料型別轉換

Boxing和unboxing是使值型別變數被當作索引型資料型別使用的二個過程。值型變數可以被包裝進一個物件中,然後再被解封回值型變數。包括內建資料型別在內的所有C#中的資料型別都可以被隱性地轉化為一個物件。包裝一個值型變數就會生成一個物件的實體(instance),然後將變數拷貝到實體中。

Boxing是隱性的,如果在需要參考型別變數的地方使用了值型別的變數,值型別變數就會隱性地轉化為參考型別變數。Boxing會影響程式碼執行的性能,因此應當儘量避免,尤其是在資料量較大的時候。

如果要將一個boxing的物件轉換回原來的值型變數,必須"明確"地對它進行unboxing。Unboxing需要二個步驟:首先對物件實體進行檢查,確保它們是由值型別變數被包裝成的;第二步將實體中的值拷貝到值型別變數中。為了確保unboxing成功,被unboxing的物件必須是通過boxing一個值型變數的值生成的物件的參考。

c# 原始碼
  1. using System;

  2. public class UnboxingTest

  3. {

  4. public static void Main()

  5. {

  6. int i=123;

  7. //boxing

  8. object o = i;

  9. //unboxing(必須明確指示)

  10. int j = (int)o;

  11. Console.WriteLine("j:{0}",j);

  12. }

  13. }

如果被unboxing的物件是無效的,或是一個不同資料型別物件的索引,就會產生InvalidCastException異常。

Jason註:其實以C#這樣簡便的寫法,boxing和unboxing對程式員根本沒有什麼負擔。這邊的重點在於隱式轉換,除了boxing下的效能影響外,是程式員常會忽略掉的地方...(呃..常用C++的人應該知道我在說什麼...orz)

錯誤5:結構(struct)與類別(class)是有區別的

C++中的結構與類別差不多,唯一的區別是,在預設狀態下,結構的存取權限是public,其繼承權限也是public。一些C++編程人員將結構作為資料物件,但這只是一個約定而非是必須這樣的。

在C#中,結構只是一個使用者定義的資料型別,並不能取代類別。儘管結構也支援屬性、函式、域和運算子,但不支援繼承和destructor。

更重要的是,類別是一種參考型別,結構是值型別。因此,結構在表達無需索引操作的物件方面更有用。結構在陣列操作方面的效率更高,而在集合(Collection)的操作方面則效率較低。Collection需要索引,結構必須boxing才適合在集合的操作中使用,類別在較大規模的集合操作中的效率更高。

錯誤6:虛擬函式必須被明確地覆寫 (override)

在C#語言中,編程人員在覆寫一個虛擬函式時必須明確地使用 override 關鍵字。假設一個Window類別是由A公司編寫的,ListBox和 RadioButton類別是由B公司的和編程人員在購買的A公司編寫的Window類別的基礎上編寫的,B公司的編程人員對包括Window類別未來的變化情況在內的設計知之甚少。

如果B公司的一位編程人員要在ListBox上添加一個Sort函式:

c# 原始碼
  1. public class ListBox:Window

  2. {

  3. public virtual void Sort()
  4. {
  5. ...
  6. }

  7. }

在A公司發佈新版的Window類別之前,這不會有任何問題。如果A公司的編程人員也在Window類別中添加了一個Sort函式。

c# 原始碼
  1. public class Window

  2. {

  3. public virtual void Sort()
  4. {
  5. ...
  6. }
  7. }

在C++中,Windows類別中的Sort函式將成為ListBox類別中Sort函式的基礎函式,在希望呼叫Windows類別中的Sort函式時, ListBox類別中的Sort函式就會被呼叫。在C#中,虛擬函數總是被認為是虛擬調度的根。也就是說,一旦C#發現一個虛擬的函式,就不會再在虛擬鏈中尋找其他虛擬函式。如果ListBox再次被編譯,編譯器就會生成一個警告訊息:

"\class1.cs(54,24):warningCS0114:『ListBox.Sort()『hides

inherited member『Window.Sort()『.

要使當前的成員覆蓋原來的函式,就需要添加 override 關健字,或者添加 new 關健字。

要消除警告信息,編程人員必須搞清楚他想幹什麼。可以在ListBox類別中的Sort函式前添加 new,表明它不應該覆蓋Window中的虛擬函式:

c# 原始碼
  1. public class ListBox:Window
  2. {
  3. public new virtual void Sort()
  4. { ... }
  5. }

這樣就可以清除警告訊息。如果編程人員確實希望覆蓋掉Window中的函式,就必須使用override關健字來顯性地表明其意圖。

Jason註:其實簡單來講,這兩個關鍵字就是讓程設人員更明確地表明企圖。override 表明要覆寫該函式,new 表明要重新定義(也就是C++裏面所說的hide...)。new 關鍵字是可以不加的,不加的話編譯器只是會給予警告,仍是可以通過編譯。用意也只是在提醒開發者該函式不會被呼叫到。

錯誤7:類別成員變數的初始化

C#中的初始化與C++中不同。假設有一個帶有private性質的成員變數age的Person類別,Employee是由繼承Person類別而生成的,它有一個private性質的salaryLevel成員變數。在C++中,我們可以在Employee的建構子的初始化部分來初始化 salaryLevel,如下面的程式碼所示:

cpp 原始碼
  1. Employee::Employee(inttheAge,inttheSalaryLevel): Person(theAge)//初始化父類別成員
  2. , salaryLevel(theSalaryLevel)//初始化成員變數
  3. {
  4. //建構子的程式碼
  5. }

這種函式在C#中是不合法的。儘管仍然可以初始化父類別,但像上面的程式碼那樣對成員變數初始化就會引起編譯錯誤。在C#中,我們可以在定義成員變數時的同時對它進行初始化:

c# 原始碼
  1. ClassEmployee: publicPerson

  2. {

  3. //成員變數的定義

  4. privatesalaryLevel=3;//初始化

  5. }

注意:必須明確地定義每個變數的存取權限。

Jason註:用C++時不少人會使用這樣的方式來初始化,稱為member initialization list。

優點是節省了一次的函式呼叫(只要呼叫 copy constructor 即可)。

錯誤8:布林(boolean)變數與整數是兩回事

在C#中,布林變數與整數並不相同,因此下面的程式碼是不正確的:

if(someFuncWhichReturnsAValue())

傳回零表示 false,否則表示 true 的想法已經行不通了。

這樣的好處是原來存在的將 "賦值運算" 與 "相等" 相混淆的錯誤就不會再犯了。因此下面的程式碼:

if(x=5)

在編譯時就會出錯,因為x=5只是把5賦給了X,而不是一個布林值。

錯誤9:switch 語句中會有些語句執行不到

在C#中,如果一個switch語句執行了一些操作,則程序就可能不能執行到下一個語句。因此,儘管下面的程式碼在C++中是合法的,但在C#中卻不合法:

c# 原始碼
  1. switch(i)

  2. {

  3. case4:

  4. CallFuncOne();

  5. case5://錯誤,不會執行到這裡

  6. CallSomeFunc();

  7. }

要實現上面程式碼的目的,需要使用一個goto語句:

c# 原始碼
  1. switch(i)

  2. {

  3. case4:

  4. CallFuncOne();

  5. goto case5;

  6. case5:

  7. CallSomeFunc();

  8. }

如果case語句不執行任何程式碼,則所有的語句都會被執行。如下面的程式碼:

c# 原始碼

  1. switch(i)

  2. {

  3. case4://能執行到

  4. case5://能執行到

  5. case6:

  6. CallSomeFunc();

  7. }

錯誤10:C#中的變數要求明確地賦值

在C#中,所有的變數在使用前都必須被賦值。因此,可以在定義變數時不對它進行初始化,如果在把它傳遞給一個函式前,必須被賦值。

如果只是通過索引向函式傳遞一個變數,並且該變數是函式的輸出變數,這是就會帶來問題。例如,假設有一個函式,它返回當前時間的小時、分、秒,如果像下面這樣編寫程式碼:

c# 原始碼
  1. int theHour;

  2. int theMinute;

  3. int theSecond;

  4. timeObject.GetTime(ref theHour,ref theMinute,ref theSecond);

如果在使用theHour、theMinute和theSecond這三個變數之前沒有對它們進行初始化,就會產生一個編譯錯誤:

Use of unassigned local variable『theHour『

Use of unassigned local variable『theMinute『

Use of unassigned local variable『theSecond『

我們可以通過將這些變數初始化為0或其他對函式的返回值沒有影響的值,以解決編譯器的這個小問題:

c# 原始碼
  1. int theHour=0;

  2. int theMinute=0;

  3. int theSecond=0;

  4. timeObject.GetTime(ref theHour,ref theMinute,ref theSecond);

這樣就有些太麻煩了,這些變數傳遞給GetTime函式,然後被改變而已。為了解決這一問題,C#專門針對這一情況提供了 out 參數修飾字,它可以使一個參數無需初始化就可以被引用。例如,GetTime中的參數對它本身沒有一點意義,它們只是為了表達該函式的輸出。在函式中返回之前,out 參數中必須被指定一個值。下面是經過修改後的 GetTime 函式:

c# 原始碼
  1. public void GetTime(out int h,out int m,out int s)

  2. {

  3. h=Hour;

  4. m=Minute;

  5. s=Second;

  6. }

  7. // 下面是新的GetTime函式的呼叫函式:

  8. timeObject.GetTime(out theHour,out theMinute,out theSecond);

Jason註:ref 關鍵字是表示傳址(傳參考值),和out的差異基本上只在本節所說的輸出,以及out必須在傳回前被賦值。C#的函式共有四種參數,傳值、ref、out和params。

 
Copyright © 大鐵與小鐵的煉鋼廠. Designed by OddThemes