•   一下子就分了手,一下子就換了工作,一下子就拿到新房子裝修老房子,每次都想寫點什麽,但是事情又很多,略微閒暇總想干點別的事情換換心情,幾次想更新博客都只是有了一絲念頭,泛起許多愁苦,只好作罷。

      人生有時候真的挺無助的,特別是你的理智發出警告而你又必須隨波逐流的時候,我很早就意識到和前女友必然會走上分手這條路。我不能改變別人什麽,只能盡力做好自己的那部分,所以到最後確實也沒有特別大痛苦。有的時候會想儅初是否太過決絕,是否還未成熟未能圓滑處事從而得到滿意的結局?每當我有這種想法的時候我都會繼而想到將來,說實在話我對這種婚姻一點都沒有信心,只能說有緣無份。

      辭職是同樣的決絕,一切都是那麽的順利,項目也正好在那個時候告一個段落,走的時候絕大部分人肯定都不相信我沒找到新工作還這麽決然辭職的事實,只能說這個公司失掉了一個公司的自尊,一個甘願成爲垃圾的公司還有什麽可以留戀的呢。可笑的是這個公司項目不斷,而人也走的不斷。一意孤行的倒行逆施只能是這個結果。不過讓我覺得可悲的是,在大多數人都能正確選擇的時候,還是會有人執迷不悟,用自己的血肉之軀無休止的向公司獻祭,來祈禱自己的前程,最後結果只能是犧牲品,難道儅頭上頂一個紅綉球的祭品就那麽自豪?

      在外包公司搞技術,真是裏外不是人,在外包公司吧你就是一個“反動學術權威”,我曾經被某同事當面問過你搞技術有什麽用,真是把我問的不知如何作答。出來吧,別的公司一看你從外包公司出來的,能給個面試機會已算不錯,只有我做完題還算態度有所改觀,不過面試的時候總是言辭裏流露出對外包公司技術的不屑。還好平時的所學最終成了救命稻草,找的新公司雖然不是理想型但是戰略上完成了目標,跳出了外包的圈子。還有就是離家好近,現在總算不用頂個熊貓眼去上行屍走肉的班了。同事大都也很好,希望在這裡能夠發揮自己的所學並積累一些經驗,在軟件架構師這條路上算是有了個啓程,我相信我能在自己喜歡的道路上走得更遠。

      最後想說停了很久的老趙的面試題解答還會堅持下去的,時間可能要等我裝修完成的九月了,因爲現在裝修住旅館很多書不在身邊。接下來的那題有點困難,但是會盡量參考齊全總結出一個滿意的答案和大家一起分享。其他最近用的技術也會寫博客留下痕跡的。

      辭職的時候用了南宋詞人陳與義的詞作爲簽名,現在也放在這篇博客最後。

      臨江仙(夜登小閣,憶洛中舊遊)

      憶昔午橋橋上飲,坐中多是豪英。長溝流月去無聲。杏花疏影裏,吹笛到天明。

      二十餘年如一夢,此身雖在堪驚。閑登小閣看新晴。古今多少事,漁唱起三更。

    分類: 隨水留真
  • ———————————————————————————————————————————————————————————————————————————————————————————

      List和T[]的区别是什么,平时你如何进行选择?Dictionary是做什么的?.NET BCL中还有哪些常用的容器?它们分别是如何实现的(哪种数据结构)?分别是适用于哪些场景?

      這些題目考查的是對集合的熟悉程度,相對比較容易,因爲大家總是在用的。

      List和T[]的区别是什么,平时你如何进行选择?

      List是一個可以定義成無限長度的氾型列表,T[]是一個氾型的數組,數組你在定義的時候不得不給他定義長度。一般都用List顯然它使用方便本身自帶的方法也多,而且他是無限長度的,可以根據需要不斷地追加。需要注意的是數組本身是繼承自Object的所以他總是在堆上分配。

      Dictionary是做什么的?

      這個是字典的氾型類,用來取代原來的HashTable。

      .NET BCL中还有哪些常用的容器?它们分别是如何实现的(哪种数据结构)?分别是适用于哪些场景?

      除了上面提到的兩個最最常用的List和Dictionary外還有如下容器。

      Queue和Stack,兩者都是不允許隨機訪問的列表,前者是先進先出的隊列,後者是先進後出的棧。

      SortedList和SortedDictionary,兩者都在枚舉的時候返回一個按照Key排好序的列表,區別在於前者使用較少的内存,而後者在添加項的時候會快一些,但是如果本來就是排好序並依次添加那麽前者更快。

      LinkedList,故名思義是一個鏈表,這個集合沒有對應的非氾型版本,使用一個鏈表是為了在其中輕鬆的插入一個元素,隨機訪問性能要比數組慢,空間佔用也更多一些,它和List不同之処在於它沒有預分配容量來用作擴充,所以也就沒有“浪費”的空間。如果你需要能在頭尾都能夠快速插入或者在中部插入,並且順序的輸出,那麽鏈表還是有用的。

    ———————————————————————————————————————————————————————————————————————————————————————————

    分類: 吹盡狂沙
  •   終於還是沒有忍住玩PSP上的遊戲怪物獵人,挺好玩的,嘿嘿。繼續更新。

    ———————————————————————————————————————————————————————————————————————————————————————————

      异常的作用是什么?.NET BCL中有哪些常见的异常?在代码中您是如何捕获/处理异常的?在“catch (ex)”中,“throw”和“throw ex”有什么区别?您会如何设计异常的结构,什么情况下您会抛出异常?

      這套題主要是考查對異常的理解,其實只要記住這句話就可以了,“僅僅處理你能夠處理的異常”。什麽叫“能夠處理”呢?就是説你抓住異常是因為你很明確一旦發生這個異常之後,你需要恢復一些狀態讓程序繼續進行下去。切忌抓住異常以後啥也不幹,然後吸收異常。

      异常的作用是什么?

      異常用於處理系統級或者應用程序級的錯誤狀態。這就會引發另外幾個問題,異常相比原來使用的返回錯誤代碼的優點在哪裏?異常處理是一種結構化的處理過程,個人認爲他最大的優點就在于將“成功場景”剝離出來,使得代碼更加清晰自然。但是異常處理相對於返回錯誤碼有一個缺點,那就是他會失去發生異常的位置。不過異常本身提供了很多幫助調試問題的工具,一般都帶有棧跟蹤,這樣位置的問題就得到一定程度的解決。還有就是IF和異常之間的選擇,我記得以前有人討論過在各種分支下是使用異常來處理各種“失敗場景”的分支還是使用IF或者SWITCH來處理呢?這其實是一個假問題,因爲異常和錯誤是有概念上的不同的,這裏的錯誤是指有違“主成功場景”的“異常場景”,爾異常是指儅程序不能完成其名字所表示功能時的錯誤。所以需要強調不要使用異常來區分各種失敗場景,異常壓根就不是用來干這件事情的!

      .NET BCL中有哪些常见的异常?

      隨便說幾個,最著名的恐怕就是那句像繞口令一樣的“未將對象引用設置到對象實例”了,還有那些基本一出現整個應用程序就被判死刑的“堆棧溢出”、“内存無法分配”異常了。

      在代码中您是如何捕获/处理异常的?

      這道題的回答可以體現你是什麽“級別”的程序員,這個級別倒不是說水平的高低,是指經常寫哪一類的程序,如果對異常的捕獲比較“激進”(經常捕獲異常)那麽這個人應該是一個應用級的程序員。如果對捕獲異常比較謹慎那麽應該是框架級別的程序員,這些人經常寫給別人使用的代碼,如果無故的使用異常處理來越俎代庖,那後果很嚴重了,這裏說一個我經歷的事,剛畢業的時候我和同事做一個WEB的項目,項目裏用第三方的Grid,那個Grid在發生異常的時候會自己報一個錯誤,你知道我們有多傻眼了吧,我們需要的是我們來抓住異常,然後報出一句對用戶友好的錯誤,但是那個控件卻幹了這麽個蠢事。

      我覺得普通程序員用的最多的CATCH就是抓住數據的異常,然後回滾數據庫來事務處理。這是一個典型的場景,因爲你明確並且能夠很好的恢復狀態。

      在“catch (ex)”中,“throw”和“throw ex”有什么区别?

      throw 重新抛出異常但是不破壞異常發生的調用棧爾“throw ex”會重置調用棧這樣捕獲異常的人會以爲代碼出錯在這裏。

      您会如何设计异常的结构,什么情况下您会抛出异常?

      首先我會盡量的使用系統定義的那些異常,如果我需要處理某一特定類別的異常,而且處理方式和通常處理方式不同那麽就考慮自定義異常,還有如果需要調用方用一種統一的方式來處理異常那麽自定義異常就是一個好的選擇。結構的話當然基類是Sysytem.Exception,盡量使用扁平化異常的層次。可以考慮用氾型類來定義異常。  

      我寫的代碼不能完成名字所說明的功能,那麽我就會抛出異常。

    ———————————————————————————————————————————————————————————————————————————————————————————

    分類: 吹盡狂沙
  •   黑色粗体為原題,普通黑色為參考答案,藍色為個人感想,紅色為要點。

    ———————————————————————————————————————————————————————————————————————————————————————————

      泛型的作用是什么?它有什么优势?它对性能有影响吗?它在执行时的行为是什么?.NET BCL中有哪些泛型类型?举例说明平时编程中您定义的泛型类型。

      這個幾乎又是一個討論不完的話題了,最早接觸氾型是上大學學習C++的時候,氾型進入C++標準可以說是C++歷史的上大事件,那時C++規範的制定已經到了最後的階段,儅天的日程已經明確不在C++裏加入新的語言特性了,但是儅委員會的幾位聼完氾型的報告後,一致通過了氾型,並且滿懷憧憬的希冀於氾型給業界帶來革命性的衝擊,不成想帶來衝擊的是Dephi和VB,快速開發工具的鋒芒迅速蓋過了C++,但是氾型這柄利器終于都在Dot Net語言和Java中被採用,影響深遠。

       泛型的作用是什么?

       氾型的作用在於“算法的重用”。(這點其實很好理解,原來的ArrayList只能接受Object,現在通過List可以接受任何類型,也就是說ArrayList的方法都被各個類型重用了。但是Dot Net的氾型有個比較制肘地方,就是你很難對數值類型(值類型)進行算法抽象,因爲這牽涉到運算符重載的問題,同時Dot Net的氾型的類型參數也不能約束成一個基元值類型(如int、double、float)。

       它有什么优势?

       第一:源代碼保護。(如果你知道C++模板對氾型的實現機制,就會知道C++在編譯的時候根據對氾型的調用,自動“内聯”了一個實現,這樣氾型的内容就暴露了,爾DotNet的實現方式就不同了,氾型類和方法會被編譯成IL,在執行的時候由JIT負責將IL變化為指定類型參數的本地代碼,從而保護了源代碼

       第二:類型安全。(這點是最顯而易見的,抛棄了使用ArrayList時各種醜陋的強制類型轉換

       第三:更清晰地代碼。因爲沒有了強制類型轉換,所以代碼自然顯得更清晰,但是使用氾型時候帶來的<>有時候確實也會讓人搞糊塗,幸好氾型方法可以用類型推斷或者using語句來進一步簡化寫法。

       第四:更好的性能,因爲值類型可以避免裝箱和拆箱所帶來的損耗(垃圾回收的次數也會減少)。(這點正是氾型神奇的地方,開發歷史上抽象能力的上升往往意味著性能的下降,但是氾型卻不是!氾型抽象了算法,但是C++和DotNet對氾型的實現能夠讓性能無損,並且更快。Java的擦除法氾型就沒有這種性能上的好處。

       它对性能有影响吗?

       對性能有積極的影響,因爲值類型可以避免裝箱和拆箱所帶來的負面影響,避免了垃圾回收,使得性能顯著提高。但是對引用類型這種影響就不明顯了。但是需要注意的是首次為一個特定數據類型調用方法時,CLR都會為這個方法生成本地代碼。這會增大應用程序的工作集大小,從而影響性能。

       它在执行时的行为是什么?

       使用氾型類型參數的一個方法在進行JIT編譯時,CLR獲取IL,用指定的類型實參進行替換,然後創建本地代碼。需要特別注意的是引用類型是共享代碼的,而對值類型就會為每一種生成獨立的一份類型代碼。但是需要指出的是引用類型的這種代碼共享並不會造成封閉類型只執行一次構造函數(就算是靜態構造函數也是這樣的)。

       .NET BCL中有哪些泛型类型?

      List、Dictionary、Queue、Stack、SortedList和SortedDictionary、LinkedList等等。

      举例说明平时编程中您定义的泛型类型。

      實際開發的時候需要自己定義氾型類型的場合並不多,個人覺得從氾型方法入手可能更好一些。個人感覺氾型的出現會替換原來一部分使用多態的地方從而提高性能和帶來更好的編譯時檢查,這樣就不需要在子類和超類(接口)間頻繁轉換了。比如你要根據情況打出各種報表,那麽先把報表類定義成氾型類從而可以共享報表一系列的算法。

    ———————————————————————————————————————————————————————————————————————————————————————————

    分類: 吹盡狂沙
  •   黑色粗体為原題,普通黑色為參考答案,藍色為個人感想,紅色為要點。

    ———————————————————————————————————————————————————————————————————————————————————————————

      在.NET程序运行过程中,什么是堆,什么是栈?什么情况下会在堆(栈)上分配数据?它们有性能上的区别吗?“结构”对象可能分配在堆上吗?什么情况下会发生,有什么需要注意的吗?

      這道題基本上同上道題,後半部分主要考察對裝箱和拆箱的認識。對於值類型和引用類型,有個比較容易犯錯誤的地方這裏我想重點說下,只要不是使用ref和out關鍵字的傳遞參數,其傳遞的必然是值傳遞。很多人包括我,都錯誤的以爲如果一個函數的參數是一個引用類型,那麽參數傳遞的也是引用傳遞,因爲對傳入參數的修改,在函數外是可見的。其實還是值傳遞,只不過Dot Net複製的不是對象本身而是指向該對象的指針。所以也是值傳遞。

      在.NET程序运行过程中,什么是堆,什么是栈?

      堆也就是托管堆(managed heap),進程初始化的時候,CLR要保留一塊連續的地址空間,這個地址空間最初並沒有對應的物理存儲空間。這個地址空間就是托管堆。(這裏面有兩個要點托管堆是連續的,還有就是他不對應實際的物理存儲空間,這樣就不會有碎片的產生,釋放的時候就需要移動對象以連續,可以參考有關垃圾回收的解答

      棧是在程序運行過程中用於保存指令,值類型變量的内存區域(一個綫程對應一個棧),棧的結構和數據結構中“棧”的結構是一樣的,“先進後出”。

      什么情况下会在堆(栈)上分配数据?它们有性能上的区别吗?

      值類型在棧上分配,引用類型在堆上分配。由於在棧上分配數據不受垃圾回收的控制,不存在垃圾回收的各種開銷,應用程序執行的時候垃圾回收的次數也會少很多,所以棧上分配顯然要比堆上分配性能上好。由於在棧上分配的變量已經包含了實例的字段所以不需要一個指針指向它。空間上的開銷也較小。

      “结构”对象可能分配在堆上吗?什么情况下会发生,有什么需要注意的吗?

      這道題我有點吃不准,第一,值類型的對象應該都是在棧上分配的,但是如果你對值類型進行裝箱那麽,也可以說分配在了堆上,但是堆上的對象是保存有原來值類型對象的副本的,其生命周期也較原來的對象更長些。第二,我不能確定CLR對於那種超大的值類型會如何分配,是直接在大對象堆上分配嘛?現在我還沒有明確的看到類似問題的解答。如果把裝箱視爲值類型對象在堆上的分配,那麽注意點就是裝箱和拆箱的注意點。

      裝箱和拆箱對字段中的值得複製動作會對應用程序的速度和内存消耗產生不利的影響。所以盡量的避免裝箱操作就是重點了。可以使用工具查看IL代碼重點注意裝箱的部分。通過類型轉換等操作來避免裝箱。氾型也是避免裝箱的一個手段(關於氾型在接下來的題目解答中會詳細描述)。

    ———————————————————————————————————————————————————————————————————————————————————————————

    分類: 吹盡狂沙