顯示具有 技巧 標籤的文章。 顯示所有文章
顯示具有 技巧 標籤的文章。 顯示所有文章

2013年10月21日 星期一

第一次互毆就上手 Swap Between Both

有時候 我們會遇到互毆的需求

像是我們要讓 A 跟 B 互毆

印出

AAA hit BBB!!!

BBB hit AAA!!!





這麼簡單一片蛋糕都不到的難度

            Member memberA = new Member { ID = 1, Name = "AAA" };

            Member memberB = new Member { ID = 2, Name = "BBB" };

            Debug.WriteLine(string.Format("{0} hit {1}!!!", memberA.Name, memberB.Name));


            Debug.WriteLine(string.Format("{0} hit {1}!!!", memberB.Name, memberA.Name));




但是別忘了 需求有時候是 會長大的幸福

重複代碼不說 有時候遇到邏輯有點兇殘的時候

Wo Ta Ma 的有時候忘了 現在到底誰是誰? 誰是攻誰是受? 誰又要對誰做什麼





此時我們冷靜的來瞧瞧有啥蛛絲馬跡

1.兩個人(物件)要做同一件事 例如 都是要打人

2.唯一的差異是 立場不同 A要打B B要打A

3.先後順序不是很重要 但是兩個人要確實都賞對方一拳





原先的代碼有什麼缺點?

1.相似內容重複代碼

2.不夠直覺 邏輯複雜時難以釐清兩者關係





若是有一個方法可以使用 我們希望他長什麼樣子?

1.泛型是基本 畢竟要什麼都吃

2.同樣的動作 我只想做一遍

3.其實當下我只在乎 哪個主動 哪個被動 骨子裡誰是誰 誰又是誰 我 TMD 一點也不在乎





綜合以上結論這個方法大概就長這樣

        public void Main()
        {
            Member memberA = new Member { ID = 1, Name = "AAA" };

            Member memberB = new Member { ID = 2, Name = "BBB" };

            SwapBetweenBoth<Member>(
                (from, to) =>
                {
                    Debug.WriteLine(string.Format("{0} hit {1}!!!", from.Name, to.Name));
                },
                memberA,
                memberB
            );
        }

        public void SwapBetweenBoth<T>(Action<T, T> action, T one, T another)
        {
            T[] array = { one, another };
            for (int i = 0; i < 2; i++)
            {
                T from = array[i];

                T to = array[(i + 1) % 2];

                action(from, to);
            }

        }




或許有人會問 這樣真的有比較好嗎?

但是至少自我感覺良好呀 哈哈哈

2012年11月28日 星期三

靜態 DB access 類別 擴展 Transaction 的方法

關於 DB 操作 通常都會包成一個專用的類別 一來避免重複程式碼 二來分層結構降低耦合

所以我有個 accessDB.NonQuery() 方法 只要 傳入 SQL 指令 跟 SqlParameter 參數 即可完成 DB 操作 其他的細節被封裝在方法之中

但是你知道的 有些人會這樣搞 例如這樣 猜猜會怎樣?

毫不意外 碰! Exception 被顯示在 Label1 上

DB... WTF...

看一下原始碼 就知道為何了

先前的寫法 早就預設所有的方法都是一次性的叫用 也就是各自為一段獨立的 DB 操作

但是實際使用上通常都是先 INSERT 一下 SELECT 一下 運算一下 再 INSERT 一下

而搞完這一輪回 才算一次成功的 "交易"

顯而易見 我需要給每個 SqlCommand 包上 Transaction 如果要期望 呼叫的人把 Transaction 寫在 T-SQL 中 那我就太傻太天真了

但是我立馬遇到了挑戰...

1. SqlTransaction 只存活在 SqlConnection 一次的開關過程之中!! 詳洽 MSDN

2. 這是一個 靜態類別!! 我沒有辦法 設一個變數(靜態類別內只能有靜態變數)來記住 SqlConnection 或是 SqlTransaction 這樣會使得同時叫用的時候發生衝突

就算真的有辦法釋出 SqlConnection 或是 SqlTransaction 的話 另外的問題則是其開關變得無法控制

當初設計這個類別 就是為了封裝 DB 操作 防止外部變因介入 這麼做等於違背初衷

沒錯 我必須在 「不提對外提供 SqlConnection 或是 SqlTransaction」的前提下 完成 Transaction 的封裝

如果是從前的我鐵定會說沒計 不然就是改成一般類別 用 new 物件的方式 獨立執行個體 則沒有衝突的問題

但是現在的我不一樣了!! 因為未來的我坐著時光機到了現在告訴了我解答!! (P.S 據未來的我表示 時光機是跟某藍色生物借的)

答案就是 我可以使用強大的委派!!



首先 封裝 建立 SqlConnection 和 SqlTransaction 成一個私有方法 並完整的包覆整個開關和交易流程 唯有叫用這個方法 才會執行完整的 DB 操作

公開方法 UsingTransactionActions 方法 是一個接受型別為 Action 參數的方法

在該方法之中 封裝了實際取的 SqlConnection 跟 SqlTransaction 的實作 也就是透過呼叫私有方法 UsingConnection

在外部使用上 不需要知道 傳入參數由何而來 (也不允許被知道)

另外將原先的 accessDB.NonQuery() 方法增加一個多載 傳入 SqlConnection 跟 SqlTransaction

請注意 唯有使用 UsingTransactionActions 方法 才有辦法在其參數(委派方法)中得到 SqlConnection 跟 SqlTransaction

UsingTransactionActions 使用方法

打完收工

2012年11月9日 星期五

善用布林 - 增加 易讀 & 易維護 & 易傳承 系列 第二彈

這個是個討論增加 易讀 & 易維護 & 易傳承 並且絕對會犧牲一些效能的系列

布林 true false 程式設計師一定不陌生

但是其實它的用途不僅僅用於表示一個屬性的真假

既然寫在這個系列,顯而易見來看看怎麼用它來增可讀可維護性



首先來看看這個if

假設一個流程有5個步驟且順序固定,但是分別在 1 3 5 需要判斷 CheckBox 勾選狀態做分歧

這樣寫有錯嗎?當然沒錯,但是顯然不好

因為同樣的結果卻進行了三次的判斷

嫻熟的 PG 都知道當一個方法返回的結果會在複數地方使用到,可以用一個變數接起來,之後只要直接使用變數,不必每次呼叫方法以提升效能

if 其實可以當作成一個特殊的方法, () 內接的參數是布林值

雖然我們是丟一組值跟運算子的組合進去,但是程式語言很聰明的有辦法把塞進去條件轉換成布林值

所以同理任何 if 判斷出的結果,都可以用布林型別的變數接住,之後不必再進行判斷

雖然看起來還是用了3個 if ,但是實際上只進行了一次的運算,後面都直接取得布林值沒有進行運算



再來還是看看if

這個情況其實不少見,在判斷某某值之前必須先判斷是不是 null

條件少的時候還 OK ,但是有時候必須判斷多個值...這時候如果又沒折行排版的話,就會看到比萬里長城還長的一條if

試試這個

2012年11月1日 星期四

善用陣列 - 增加 易讀 & 易維護 & 易傳承 系列 第一彈

這個是個討論增加 易讀 & 易維護 & 易傳承 並且絕對會犧牲一些效能的系列

通常一組功能按鈕由於常常在各處使用,為了避免重複程式碼,不管是做成使用者控制項還是利用樣板來使按鈕組唯一都是常見的做法

但是共用謂之必須判斷所有的情況,因為實際上有很多因素左右這些按鈕的行為

像是新增頁不該出現[查看],查看頁不該出現[儲存]等等的顯而易見的邏輯互斥

為了在各種情況下判斷按鈕的顯示,不知不覺就寫了這串CODE

如果各位看官覺得這串東西,很簡單明瞭,對應十分分明的話,恭喜您絕對是擁有血輪眼

到底要怎樣才能既明瞭又能避免多次的宣告Visible呢?

早在標題就說破謎底了,就是使用陣列

陣列不但可以整齊的整理這組按鈕之外

更重要的是它可以foreach

嫻熟的PG都知道不管怎樣重複類似相近的鬼東西,想辦法用迴圈,就對了

這裡使用了一組Button[] 跟 各種情況顯示與否的 bool[]

最後不論過程如何 只需要 for迴圈 媒合 Button[] 跟 bool[] 即可

雖然我不知道這樣是否有比較乾淨明瞭,至少我是信了。

雖然這邊刻意對齊排版讓邏輯變得視覺化,但是實際上保持一致的寫作風格就好了

以上。

2012年10月6日 星期六

利用 泛型委派 Action 與 Func 減少不必要的 公用方法

基礎知識 請拜 小朱大神人文 [.NET] 由委派演進到 Lambda Expression
http://www.dotblogs.com.tw/regionbbs/archive/2012/08/15/from.delegate.to.lambda.aspx

假如剋戶要的效果像這樣 - 一個偵測句子有無特定關鍵字的文字小遊戲 (雖然真實的剋戶要求絕無可能這麼簡單)

新到不能再新的初心者寫出這段吐槽到不行的CODE

身為一個職業的嫻熟PG,絕不允許重複代碼,於是大刀砍~

抽抽抽~重複的地方全抽出來寫個公用方法,一片蛋糕

但是有時候並不是很好(雖然自我感覺良好),因為如果程式碼重複的代碼僅限於一個方法之中

如果抽成公用方法方法的話,這將是永遠只有同一叫用來源的方法

這不打緊,如果方法的順序排的很亂,移至定義跳來跳去還沒看CODE就先轉暈了

這還不包括封裝的方式不夠好,不小心被誤用,由其他的來源叫用這個公用方法



訴求很簡單:有沒有辦法(限制)在一個方法之中,把重複的代碼包起來執行

答案很簡單,使用委派就好了

但是直接使用自訂的委派物件不是個好作法,如上所言

不會在別的地方用到,所以特地宣告一個委派物件有點多餘,甚至有可能占用掉一個別人可能需要的命名



我想得到的 .NET 不太可能沒想到

神人文:http://www.dotblogs.com.tw/atowngit/archive/2011/02/23/21523.aspx

參拜完神人文章之後就知道有現成的委派物件可以直接使用。



利用Func我將3個小方法封裝在 doWork 之中,絕無可能被其他方法誤用

而且泛型委派可以直接取得同層的變數

這個案例其實適合使用Func,但是懶得再寫一個Action的案例所以直接硬改

因此 lineMaker 為了判斷來源 多了一個 switch

實際上要用 Action 還是 Func 應該遵照需不需要有回傳值來做決定

2012年9月26日 星期三

Reflection 反射吧!男孩

個人寫程式只有兩條大守則

第一條:比起效能我更在乎易維護

第二條:絕對不要違反第一條



範例:

有時候剋扈或牢版不希望網站上的圖片實體路徑被裸體公開

因為實體路徑被知道了就會被任意玩弄

想想我們的老朋友 泛型處裡常式

利用它可以搞些卑鄙手段防止被玩弄

例如檢查 登入 Session 之類的東東 確認 某些狀態

若是非登入狀態 將無法取得圖片

這裡沒搞什麼手段 就只是很簡單的藉由讀取路徑再 Response.BinaryWrite 輸出 圖片

圖片路徑就變成這樣 看不出原始路徑

http://localhost:4024/getImage.ashx?name=smile.jpg&type=Jpeg



但是上面說的東東跟這篇的主題沒啥關係 ._.

重點在於這裡為了將圖片轉成 byte[] 用到了一個 ImageFormat

裡面長這樣 用來告知圖片是何種類型

為了支援所有類型 不知不覺它就變成這樣



這樣寫有錯嗎? 當然沒錯 但是不夠優雅呀

打 GAME 要風騷走位優雅輸出 打CODE 也一樣

反射吧!男孩 請回想程式守則第一條



雖然我(有可能)犧牲了效能 但是程式碼變得更簡潔了

而且若是日後 ImageFormat 有任何屬性(Property)增減異動 我也不需要修改程式碼



P.S. 為了寫那個 switch 複製貼上手很酸 -.-

2012年8月30日 星期四

就是不給 New 之 封裝建構子

不給 New~ 不給 New~ 我就不給 New 物件~ 我就不給New呀 不給New呀 不給你New呀~



有時候某物件只希望以特定方法產生,而非所有人都能 new ,這時候只要封裝建構子即可

上面說的有點抽象,但是這個一定有看過

SqlDataReader 必須藉由 ExecuteReader() 產生

SqlDataReader 有點像是代理 SqlCommand 處理一些功能

他需要某些 SqlCommand 裡面的東東

但是如果誰都能 new 一個SqlDataReader

那可能會因為 缺少某些 SqlCommand 裡面的東東 而出錯

所以統一由 SqlCommand 所提供的 公開方法 來產生 SqlDataReader 物件

以確保每個 SqlDataReader 都能正常運作



正經範例如下



類別跟介面

實際運作的主類別



今天想要專業的人才說話 所以改寫如下



類別跟介面

實際運作的主類別

等等,なにかおかしい



這下演講將變得有點兒糟

那就不給 New 吧



類別跟介面

實際運作的主類別



這下就能徹底擺脫熊○的騷擾了

只有鬼知道的C# 第一彈 建構子小秘密

這個系列只介紹一些 少用 少見 或者 我孤陋寡聞 不知道的東西

[C#.NET] 為建構子建立正確的初始化

原本是貼另一篇的連結的 結果網頁竟然 404 了 沒備份真是不智 -.-

2012年8月26日 星期日

一秒看破 static

static 靜態 是個很奇妙的 關鍵字

早在 哈囉,世界 的時候就看到 static void Main() 這個 加了 static 關鍵字的方法

但是在真正了解 static 的意義卻又是很久以後的事了

2012年6月24日 星期日

數學不好的時候使用While迴圈吧






總之遊戲規則是這樣的

1.每頁一定要有HEADER

2.FOOTER只要最後一頁出現

3.除內容行外不允許跨頁

 

 

假設一頁20行

HEADER和FOOTER各需5行

如果內容行小於10需要一頁,FOOTER在第一頁

如果內容行大於10小於15,需要兩頁,第二頁只有HEADER和FOOTER沒有內容行

如果內容行大於15小於25,需要兩頁,FOOTER在第二頁

如果內容行大於25小於30,需要三頁,第三頁只有HEADER和FOOTER沒有內容行

如果內容行大於30小於40,需要三頁,FOOTER在第三頁

好吧有點饒舌看圖

 

 

問內容X行時,迴圈要怎麼寫?

 

 

這時候就會開始找紙筆還是敲計算機把公式生出來然後FOR迴圈加1減1加X減X取商數餘數之類的弄半天

尼瑪,林北數學爛到爆,這下杯具了

 

 

試試While迴圈吧

管他什麼10 15 25 30

只需要知道

1.這頁內容結束沒,如果沒結束就換頁

2.結束時那頁有沒有內容,如果有又超過10行的話再加一頁

 

 

 

 

結果8連彈

2012年6月10日 星期日

生死格鬥之浪打委派 第一彈 List Sort()、Find()、FindAll()、Exist() 豬走路範例






回憶起我們小時候~ 第一次見到List

閉上眼睛就能感受~ 哇太神啦 不用設大小的伸縮陣列

在我們心中慢慢流動的溫柔~ Array 神馬的再也不用了

 

但是很快的我就發現我對這個新夥計還不夠了解

因為我竟然不會用

List.Sort() → 排序T

List.Find() → 找出一個T

List.FindAll() →找出多個T

List.Exist() →判斷T是否存在

這幾個神奇方法

直到我參拜了前輩的文章

[ASP.NET]利用List的Sort()、Find()、FindAll()、Exist()來解決一些問題

我就像草叢倫看到蠻三刀旋風斬的時候一般,大嘆:神技術,我來試試

果然我還只是個2B,頂多依樣畫葫蘆的假裝會用,實際上在搞什麼鬼還是有看沒懂

老師跟我說:沒關係你還小還不懂,長大就會懂了。

那什麼時候長大呢?

沒錯,現在就長大了。

 

 

 

 

老師的範例其實寫得很明白了,但是為什麼我還是看不懂呢,很簡單,就是這範例還太高檔了,不是當時豬腦的我可以理解的

我們降一個檔次直接用最常用的List<int>保證果斷明白

 

 

 

 

考試囉,如果有好好聽課的話,下面的題目超簡單的

 

 

 

 

神馬?你說沒介紹Sort()、Find()、FindAll()?

不是說了是豬走路範例了嗎,看過一個就應該會走路了