About

塵世間一位迷途師程工,「三單」(單眼、單車、單身) 幫初階會員。

| Posted by LittleLin

[C#][筆記] 關於列舉 (enum) 型別特性的整理

本篇算是整理,針對列舉 (enum) 型別的一些使用上的心得。

首先要先點出的是,列舉是 Value Type,不是 Reference Type,因此在列舉型別物件中,儲存的值不會是 null,所以如果錯誤使用它的話,有時候會產生意想不到的結果。

第二點是,從前一篇 [C#][筆記] default 關鍵字針對不同型別的回傳值整理 文章的實驗結果中,我們可以看到,針對列舉型別,使用 default 關鍵字,回傳的值是 0。

我們舉下面的 Sample Code 做為範例 (這是真實案例,我從別人的 code 中抽出來的),程式中我們定義了一個列舉 TestEnum,有 Value1、Value2、Value3 三個成員。

/// 
/// 測試用列舉
/// 
public enum TestEnum
{
    Value1,
    Value2,
    Value3
}

在主程式中,我們有一個 List 變數,名稱為 testList,內含有列舉中的 Value1 與 Value2 成員。程式的需求,是判斷這個 List 變數中,有沒有包含 Value3 這個列舉值成員。

因為有人把列舉視為 Reference Type,因此就寫出了以下的程式碼︰

bool isListContainValue3 = false;
List<TestEnum> testList = new List<TestEnum>() { TestEnum.Value1, TestEnum.Value2 };
isListContainValue3 = testList.FirstOrDefault(element => element == TestEnum.Value3) != null;

// 總是印出 True
Console.WriteLine(isListContainValue3);

我們先不管誤用 FirstOrDefault() 這個 method 來做「判斷一個 List 是否包含某個值」的問題,上述的程式,如果我們真正執行的話,我們會發現,程式永遠會印出 True,即使上述 testList 並不包含 Value3 這個列舉成員。

會出現這問題,是因為錯誤將列舉視為 Reference Type,認為如果在清單中查不到成員的話,default(TestEnum) 會回傳 null 值。

但我們已經知道,列舉其實是 Value Type,因此列舉變數是不能儲存 null 值的。在此例中,testList.FirstOrDefault() 這個 method 會回傳的是 default(TestEnum),也就是 TestEnum.Value1 這個列舉成員。也因此結果永遠不會是 null,印出來的值則永遠印出的是 True。

算是以一個例子,來說明誤解列舉型別,在某些情形下,是真的會造成問題的。

最後,以上述的需求來看,其實可以直接使用 List 類別的 Contains method,就可以了︰

isListContainValue3 = testList.Contains(TestEnum.Value3);


References:

| Posted by LittleLin

[C#][筆記] default 關鍵字針對不同型別的回傳值整理

default 是在 C# 中,用以取得指定型別 (type) 的「預設值」的關鍵字,簡單的範例用法如下︰

default(型別);

從 MSDN 上關於 default keyword 的說明頁面中,整理「預設值」的回傳規則如下︰

  • 如果指定的型別是 Reference type 的話,則 default 關鍵字回傳值是 null
  • 如果指定的型別是數值類型 (numeric) Value type 的話,則 default 關鍵字回傳值是 0
  • 如果指定的型別是可為 null (nullable) Value types 的話,則 default 關鍵字回傳值是 System.Nullable<T>
  • 如果指定的型別是 struct 的話,則 default 關鍵字回傳值是一個新的 struct object,但 struct object 中的每個成員的值,內容一樣會遵照上述三個規定做設定

但上述的描述中,我們看到,MSDN 中沒有針對像 DateTime、列舉等型別的預設值做出說明,所以我撰寫了簡單的測試程式,來做這部份預設值的實驗。

為了測試方便,所以我定義了一個類別、一個結構與兩個列舉型別 (一個有針對成員設定值,另一個則沒有),以方便測試,型別定義整理如下︰

類別︰DemoClass

/// 
/// 測試用類別
/// 
public class DemoClass
{
    /// 
    /// Value Type 屬性
    /// 
    public int ValueTypeProperty { get; set; }

    /// 
    /// Reference Type 屬性
    /// 
    public List ReferenceTypeProperty { get; set; }
}

結構︰DemoStruct

/// 
/// 測試用結構
/// 
public struct DemoStruct
{
    /// 
    /// Value Type 屬性
    /// 
    public int ValueTypeProperty { get; set; }

    /// 
    /// Reference Type 屬性
    /// 
    public List ReferenceTypeProperty { get; set; }
}

列舉︰DemoEnum (指定每個列舉值,背後代表一個整數)

/// 
/// 測試用列舉 (指定每個列舉值,背後代表一個整數)
/// 
public enum DemoEnum : int 
{
    Value1 = 1,
    Value2 = 2
}

列舉︰DemoEnumWithoutValue (不指定每個列舉值,背後代表一個整數)

/// 
/// 測試用列舉 (不指定每個列舉值,背後代表一個整數)
/// 
public enum DemoEnumWithoutValue : int
{
    Value1,
    Value2
}

針對各型別的 default keyword 回傳值,我整理如下表︰

型別 default 回傳值 說明
List null Reference Type 回傳 null
string null
int 0 數值型的 Value Type 回傳 0
int? null 回傳 System.Nullable<int>
DateTime 0001/1/1 上午 12:00:00 即為 DateTime.MinValue
DateTime? null 回傳 System.Nullable<DateTime>
DamoClass null
DamoStruct ValueTypeProperty = 0
ReferenceTypeProperty = null
結構的每個成員,其值設定為 default 關鍵字回傳的預設值
DemoEnum 0 列舉成員值有設定數值,則回傳 0 
DemoEnumWithoutValue Value1 列舉成員值沒有設定數值,則回傳此列舉的第一個成員 (其值為 0)

補充說明︰

1. 針對 DateTime 型別,首先要先注意的是,DateTime 型別是 struct,所以是 Value Type 而不是 Reference type

而 DateTime 內部的結構,其實是記錄一個 ulong 型別的 ticks (千萬分之一秒) 屬性值。當我們對 DateTime 型別做操作或是取得日期資訊 (ex: 年、月) 時,背後其實是使用 ticks 屬性值來做相關的計算。

因此所謂的 DateTime.MinValue,其實就是 ticks 屬性為 0 的 DateTime object,而 .Net Framework 定義 ticks 屬性值為 0 的起始點為︰0001 年 1 月 1 日午夜 12:00:00。

而 DateTime 型別因為是 struct,因此 default(DateTime) 會回傳一個 DateTime object,其中的 ticks 屬性因為是 long 型別,所以預設值為 0。因此 default(DateTime) 的值會與 DateTime.MinValue 值相等 (因此兩者內部的 ticks 皆為 0)。

2. 另外在這邊要注意,在列舉型別中,如果沒有特別針對成員設定值的話 (像 DemoEnum),其成員的值是從 0 開始編號。因此 DemoEnumWithoutValue.Value1,背後的值其實是 0,所以 default(DemoEnumWithoutValue) 會顯示 Value1,其實是合理且一致的。

測試程式︰

測試程式我已經上傳到 GitHub,網址如下︰https://gist.github.com/LittleLin/5390639,可以使用 SnippetCompiler 來運行上面的測試程式碼,或是開 Visual Studio 執行也可以。

References:

| Posted by LittleLin

騎 ubike 下班滿月感言

ubike 下班已經進入第五週了 (當然是在沒下雨的狀態)。

話說從頭,當初原本是想買一台新的單車,可以環島上班兩相宜的。預算都撥了,候選名單也列了幾台車,原本打算去實體店面試騎看看,比價價格不要差太多就可以下手了,有機會還可以幫公司衝一下業績。

然後就看到了 ubike 的方案,突然想說,比起真的買一台單車,或許租車會是更經濟的選擇,可以省去保養車子,停車跟擔心車子被偷等要關心的事情,對我這個懶人來說似乎不錯。

另外從費用來看,ubike 目前租車的費率,一小時只要十元,(前 30 分鐘免費,再來每 30 分鐘是十元),而我平常上班搭捷運,一趟要 20 元。所以不考慮花費時間的話,騎 ubike 比起搭捷運,也要來得划算得多。

總之綜合上述,就決定暫時擱置買單車的計劃,開始騎 ubike 下班的日子了。目前歷時四週,覺得非常不錯,下班時騎 ubike 回家,腦袋還行就邊騎邊整理思路,不行時就一路放空,整體來說其實還滿不錯的。希望可以繼續保持下去啦!

| Posted by LittleLin

MongoDB 全文搜尋 (Text Search) 簡易功能測試

三月份 MongoDB 推出了 2.4 版,在其 Release Note 中,最大的亮點就是正式推出了 全文搜尋 (Text Search) 功能。

雖然看 Text Search 支援的語言列表中,並不支援中文,但因為搜尋是個我很感興趣的功能,所以還是來試玩看看,整理一下簡單的測試過程。

1. 到官網下載最新版的 MongoDB 2.4 

2. 使用以下指令,啓動 MongoDB

啓動的參數需加上 —setParameter textSearchEnabled=true,以告訴 Server 要啓用 Text Search 功能。

$ mongod --bind_ip 0.0.0.0 --dbpath=D:\tmp\FullTextTest --rest --setParameter textSearchEnabled=true

3. 新增測試資料

3.1 準備測試資料

我準備了一個資料檔 insert.js,在 News collection 下新增測試的文件,每個文件有兩個欄位︰標題 (Subject)內文 (Content)

因為只是簡易測試,所以我只有簡單整理三篇文章,其中兩篇是中文的新聞,另一篇是英文的 Blog 文章。當然如果未來想增加測試文件的數量,只要修改這個檔,加入文件內容就可以了。

內容如下︰

var docs = [{
        "Subject": "「九宮格」都會利用 鐵捕讚建仔:真的不一樣",
        "Content": "中國時報【(執筆:楊舒媚、江慧真)】 中華隊當家鐵捕高志綱對旅外巨投王建民的球有什麼評價?回首2002年釜山亞運,王建民是小聯盟球員,高志綱接建仔的球直覺地說,「哇,應該是大聯盟級的啊,還是大聯盟選手真是高過想像,這樣的程度都還沒辦法上去?」這次經典賽正面迎向王建民,高志綱更驚艷,「在大聯盟待過,他投球的感覺真的不太一樣。」建仔不太需要配球,「只要讓他自己保持好的節奏,結果不會差太多。」高志綱讚嘆,王建民的伸卡球太好了,且很清楚地知道怎麼去利用好球帶位置,「不是邊邊角角兩邊投得準就好,是九宮格都會利用,光是直球,就懂得用不一樣的角度嘗試。」對於郭泓志,「台灣出來的選手找不到像他這麼霸氣的!」高志綱形容,但小小郭上來時,多半是緊急狀況或球賽後半,「要慎重一點,讓他投得更有自信。」"
    },{
        "Subject": "MLB/黑田博樹展大和魂 受傷仍不想被取代",
        "Content": "記者陳浚錡/綜合報導 洋基隊日籍右投黑田博樹4日遭球擊中右手中指,即便接受初步檢查沒有大礙,第二天他仍感到有點不舒服,但他意志堅強不想被取代,接受訪問時表示,還是希望能夠趕上第二場先發。黑田第一戰先發對紅襪狀況不理想,首局就挨3支安打掉1分,2局上維多里諾(Shane Victorino)擊出投手前強襲球,黑田本能反應想伸出右手接,結果打到中指,雖然一開始還待在場上,但一連串的保送後仍被迫退場休息,而且表情痛苦。經過X光檢查以及斷層掃描,黑田手指骨頭並沒有斷,但他還是覺得有些不適,「我得說感覺並不尋常,打到的地方還是有點不舒服,我認為球打到手本來就會痛了。」這位38歲投手表示,他目前的底線就是要趕上下一場先發,不過還是會在6日進牛棚練投後確定狀況。黑田近兩季皆全勤出賽,投球局數更超過200,是洋基隊倚重的長局數先發投手,若他傷得比想像中嚴重,投手輪值勢必元氣大傷。不管黑田能不能投,洋基已經先做好備胎,由前役投5.1局失1分的右投華倫(Adam Warren)待命,去年是華倫大聯盟的第一年,但也只出賽1場,先發僅投2.1局被擊出8支安打,包括2支全壘打失6分,最後靠著洋基堅強打線逃敗。"
    },{
        "Subject": "MongoDB Full Text Search",
        "Content": "Yesterday we released the latest unstable version of MongoDB; the headline feature is basic full-text search. You can read all about MongoDB's full text search in the release notes.This blog had been using a really terrible method for search, involving regular expressions, a full collection scan for every search, and no ranking of results by relevance. I wanted to replace all that cruft with MongoDB's full-text search ASAP. Here's what I did."
    }];

db.News.insert(docs);

3.2 執行新增動作

在命令列下,執行以下指令,在 TextSearchTest DB 下,新增測試文件︰

$ mongo 127.0.0.1:27017/TextSearchTest insert.js

到此,我們已經將 MongoDB 的測試文件給建立好了。接下來就是建立全文索引,和測試搜尋的功能。

4. 建立全文索引

4.1 連接 DB

我們以下指令,連接 TextSearchTest DB︰

$ mongo 127.0.0.1:27017/TextSearchTest 

4.2 建立全文索引

在 MongoDB 下,以下列指令 ,建立 News collection 的全文索引︰

db.News.ensureIndex(
    {
        Subject: "text",
        Content: "text"
    }
);

5. 搜尋測試

再建立全文索引後,接下來就可以正式做搜尋功能的測試了,搜尋功能非常簡單,以要對 News collection 搜尋為例,搜尋指令如下︰

db.News.runCommand( "text" , { search: "搜尋關鍵字 " } )
我們分成英文與中文的功能測試︰

5.1 英文測試

簡單搜尋一下 MongoDB 這個詞︰

db.News.runCommand( "text" , { search: "MongoDB" } )

image


可以看到,結果是我們所預期的,最後一篇關於 MongoDB 的 blog 文章。

5.2 中文測試

我們再針對 王建民 做搜尋︰

db.News.runCommand( "text" , { search: "王建民" } )

image


結果則是無法正確的搜尋,我們所預期的第一篇中文新聞沒有顯示在搜尋結果中。

本文針對 MongoDB 新推出的 Text Search 功能,做一個非常簡單的功能測試。就目前測試的結果,要將 MongoDB 做為中文文件的搜尋引擎,現階段應該還是沒有辦法。或許後續的版本會再將中文搜尋納入支援的語言也不一定。

| Posted by LittleLin

小故事,大道理 - 組織訊息傳遞的小小分享

分享晚上和朋友吃飯,他說的小故事。

朋友公司最近找了一間,類似麥肯錫這樣的管理顧問公司,來幫公司成員上課。在課程中,顧問帶領學員們玩了一個「組織訊息傳遞」的遊戲,基本的遊戲規則整理如下︰

1. 所有人分成 4 組,每組有 n 個人,代表組織訊息傳遞上會有 n 個階層
2. 每組人都排成一長列,只有隊伍最前面的 team leader 可以睜開眼睛,其他人的眼睛都要閉上
3. 每個隊伍的最後面,都有一顆球
4. 顧問會在前面翻牌,只有牌子是紅色,team 才可以去拿球。team leader 必須把他看到的資訊,一層層傳遞到隊伍的最後方,讓最後面的 team leader 知道這一次要不要去拿球
5. 每輪遊戲,最先正確拿到球的隊伍有加分,不該拿球的時候去拿球的隊伍,會扣分

比較有趣的是比賽的過程,各組想的方式各有不同。

有的隊伍想的是,比較簡單的做法。就是 team leader 跟後面傳遞的方式,是 team member 一個個拍自己後面成員的手心,拍一下代表要拿球,拍兩下代表不拿球,一層層傳到最後面的 team member。

但他們這組是最後一名,主要原因有兩個︰

1. 一層層拍手心的方式,太慢且沒效率。
2. 組織多傳遞了「不要去拿球」這個資訊。實際上只應該在需要拿球時,再做訊息傳遞就可以了,不必要的訊息反而變成雜訊了。

而第一名的隊伍,想的方式就比較有效率,他們將皮帶解下來,綁成一長條。所有的 team member 都拉著這條皮帶,當講師翻出紅牌時,當 team leader 把皮帶一拉,所有的 team member 都會同時知道「要拿球」的訊息,而且效率很高。

而當不需要拿球時,team leader 與 team member 完全不需要做任何事情,中間也可以避免資訊傳遞過雜,反而造成雜訊的情形。

這個小故事帶給我一些啟發,所以在睡覺前把它記錄一下 :)

| Posted by LittleLin

[趣事] 02/28 坐車上台北,看到真人表演搭訕

補記一下昨天到新竹看完燈會,從新竹搭末班區間車上台北,親眼看到真人搭訕的趣事 (之前都是看電影,沒看過真人表演)。

昨天上車後,因為人滿多沒有位置,所以我就拉著拉環,打算站回台北去。旁邊站著一個滿漂亮的女生,在我右手邊玩著手機。

然後車開到桃園吧,隔壁車廂就有個大叔走過來,問說︰

「小姐,請問洗手間在哪邊啊?」

那女生就向那大叔,指著洗手間的方向。然後大叔就突然傻笑講一句︰

「小姐,你好漂亮喔~~」

那小姐沒理他 (可能也不知道要怎麼反應吧),我當下是嚇到,沒想到無預警看到這齣,大概過了三秒後,大叔又自己解套︰

「不理我~~哈哈哈~~~」

然後大叔就在哈哈聲中,淡出這個車廂,留下不知道要怎麼辦的小姐 (她強裝鎮定的繼續玩著手機),和一群面面相覷的乘客們……。

| Posted by LittleLin

[Git] Windows 下,設定 Git 的 Commit Log 編輯器為 Notepad++

雖然我知道很多朋友在 Windows 下,是使用 msysgit + TortoiseGit,直接操作 GUI 來做 Git 的操作,但很多時候使用命令列才是男人的浪漫啊!

而在命令列下,最常操作的情境之一,就是要進行程式的 commit。而因為 msysgit 下內建的 vim 編輯器,對中文的支援其實滿不好的,所以在使用它來撰寫 commit log 時常會讓我感到困擾。

本篇整理如何在 Windows 下,將 Git 的 Commit Log 編輯器,設定為我自己常用的 Notepad++ 編輯器的步驟。當然照著這步驟,要設定為其他朋友慣用的編輯器,應該也不是太困難才對,可以參考服用。

步驟其實只有兩動,相當簡單︰

1. 建立一個 script 檔,我的檔案路徑置於 C:\LittleLin\Git\npp.sh

2. 在 Git 環境下,改變預設的編輯器設定︰

這樣就可以了,是不是相當簡單呢?

| Posted by LittleLin

[補發] 2012 年最後的夕陽,2012/12/31 攝於台中高美溼地。

| Posted by LittleLin

[Quora] 好文分享: 是什麼造就了好的軟體工程文化?

這兩天看到 Quora 上一個不錯的問題︰What makes a good engineering culture? (是什麼造就了好的軟體工程文化?) 這個其實也是最近我在思考的問題之一,而評分最高的答案,剛好是一位 Quora 的軟體工程師所回答的。

因為回文的內容我還滿喜歡的,所以試著用爛爛的英文跟中文,來翻譯文章中提出來的 10 點想法。我儘量逐字句翻譯,冒號後算是我的小小理解或註解這樣。對細節有興趣的朋友們就回頭去看看內文吧︰

[Edit]
關於第 6 點 Shared Code 的觀念,在搞笑談軟工部落格中,也有一篇好文︰Shared Code:讓我們變成博格人吧,解釋了這個觀念,可以順便參考閱讀。

  1. Optimize for iteration speed. (迭代速度的最佳化︰加速產品/專案迭代的速度)
  2. Push relentlessly toward automation. (不顧一切的朝自動化方向推進︰儘量將瑣事自動化、排程化)
  3. Build the right software abstractions. (建立正確的軟體抽象化架構︰保持核心架構簡單,可以有效提升團隊效率,和方便採用第三方架構或函式庫)
  4. Develop a focus on high code quality with code reviews. (採用 code review 的方式,使團隊聚焦於高品質的程式碼)
  5. Maintain a respectful work environment. (建立並維持一個互相尊重的工作環境)
  6. Build shared ownership of code. (建立程式碼共有的環境︰專案中的程式碼,屬於團隊中的所有人所共有。團隊成員對系統中的程式碼好壞具有集體意識,對於不良的設計皆可以動手進行調整修改)
  7. Invest in automated testing. (投資於自動化測試)
  8. Allot 20% time. (20% 時間的分派︰典型的例子是 Google,員工擁有 20% 開發自己作品的時間)
  9. Build a culture of learning and continuous improvement. (建立一個持續學習與改善的文
  10. Hire the best. (聘用最好的人)
| Posted by LittleLin

2012 年終感言

2012 年,世界最終沒有末日,大家都還在,所以還是和往年一樣,試著來寫寫感言。

和之前的年份相比,今年對我來說是個很特別的一年。我離開了服務三年的公司,做了一些目前還看不出是好是壞的決定,調整了一些生活上因子的比重,嘗試做些不一樣的事情。

我體驗了不少好事和壞事,也拓展了不少的生活經驗。

三年後重新開始找工作,從在前公司負責面試人,變成找工作時被面試。在整理履歷的過程中,發現自己這三年過得真的可以稱得上是「充實」,辛苦了!

一個人出去旅行了兩次,雖然是很弱的國內旅行,但從中間認識了不少朋友,甚至還有對岸的朋友。遭遇了一些經典事件 (好在沒遇到鬼),眼界經驗都有打開,也希望來年可以往國外自由行發展。

開始學習拍照,從一開始什麼都不懂,到現在比不懂再好上一點點。運氣好遇上好景,還可以拍出一兩張好照片,丟上去 FB 和朋友炫耀一下。

進戲院看了超過 40 部首輪片,在電影觀賞中享受 2 小時的跳脫生活,是每週最大的享受之一。

和一些好朋友討論一些合作,雖然目前還沒什麼成果,但希望明年,可以慢慢孵出些自己滿意的東西和作品出來。

當然今年遭遇最大的難題,就是做出各種決定時的不確定感。很多時候其實我並沒有那麼篤定,離開習慣的環境和舒適圈,總是令人覺得前途茫茫。但就是在深深的思考後,覺得該是調整的時候,然後我就做了。

「或許未來我真的會為今天的決定後悔,但如果現在不做,我現在就會開始後悔。」

大概就是這樣的心情在支撐自己吧,講的很玄,但其實就是這樣。

以上就是通篇沒什麼重點的感言,不管怎麼樣, 2012 年,謝謝大家的照顧了,新的一年希望大家多多指教囉 :-)