2014年8月17日 星期日

一秒看破 C# Attribute

...我們絕非從未謀面

...總是悄悄的守候在我們身旁

...默默犧牲奉獻幫我們做了許多事

他是我們 最熟悉的陌生人

~ C# Attribute ~





此屬性 (Attribute) 非彼屬性 (Property)

對岸管他叫 "特性"

這裡還是叫他 Attribute 吧

M$ 的說明:

C# 提供了一個定義宣告式標記 (Tag) 的機制,此宣告標記稱為屬性 (Attribute),可以讓您在原始程式碼中放置一些實體,來指定額外的資訊。屬性所包含的資訊可以在 Run Time 時透過反映來擷取。您可以使用預先定義屬性 (Attribute)或者您可以定義自己的自訂屬性 http://msdn.microsoft.com/zh-tw/library/aa288059(v=vs.71).aspx





我們無時無刻都能瞥見 Attribute 的身影

加上 Attribute 我們的程式就被賦予了超能力

但是...Why?

為什麼明明我們什麼都沒做 只是加上 Attribute 程式就會多出一些能力呢?





答案顯而易見 自然是冥冥之中有股神秘的力量 Framework 幫我們完成了這些事

在 C# 物件導向 裡面通常都是靠 [繼承] 承接或擴充功能

但是[繼承]是一種垂直鏈狀的概念

當[繼承]深度越深的時候[可維護性]相對的就會變低(因為太多層了)

所以有句口訣叫做 多用合成 少用繼承

設法把不同功能拆分成 單一職責(Single Responsibility Principle)的小類別

再合體成模組級別的大類別 (怎麼合體自然也有一堆花招 EX:DI、IOC etc)

但是這僅止於 設計類別時內部自嗨的層面

有的時候需求來自是外部的





例如有個[顧客]類別有其自身的屬性方法

另外還有[店家]類別

[店家]類別自然無權干涉[顧客]類別的內部行為

理所當然[店家]對[顧客]提供服務

即便[店家]對外宣稱:我們無分男女、宗教、種族、階級、黨派,在服務上一律平等

但是用膝蓋骨想就知道那肯定是ㄊㄇ唬爛的

所以[店家]類別需要針對不同的[顧客]提供不同等級的服務

或許有人覺得那就給[顧客]一個叫做[顧客等級]的 Property 就能解決了

事實上的確可行 但是卻不是很合理

因為 Property 是屬於類別內部擁有的資訊 由類別決定如何提供給外界使用

如果[顧客]可以任意決定自身的[顧客等級]那未免也太可笑

這個時候應該使用 Attribute

Attribute 主要是給外部使用的資訊 LIKE 設定 貼標籤 註解 表述

以便[店家](外部)在使用[顧客](貼 Attribute 的類別)的時候能夠達成[提供不同等級的服務]的需求





講了那麼多 我想還是沒人懂 Attribute 到底在玩什麼把戲 (因為這就是 Attribute 的魅力特色呀 <3)

馬上來玩玩就對了





首先有兩個頁面 External 跟 Internal

分別使用 ExternalBulletin 跟 InternalBulletin

共用的部分繼承抽象類 Bulletin

Bulletin 在建構子 會使用 ArticlesFactory 來產生文章

Articles POPO 類 單純 DTO

如今響應個資法 需要 Articles 裡面的人名都改成 OO

這是一個外部因素帶來的改變 實際上 Articles 的本質不應該被改變 只是呈現的時候 人名必須要變成 OO

所以這裡設計一個 SilencerAttribute

裡面有個 SilencerMode 用來決定模式

現在可以給 ExternalBulletin 或 InternalBulletin 掛上 Attribute 了

基本上要掛哪個都可以(水平特性)

只是情境上是 外部的 Bulletin 需要保密

而內部的 Bulletin 則需要看到原始 Articles

只是掛上 Attribute 會怎樣嗎? 會有什麼事發生嗎??

用肋骨想就知道 當然不會怎麼樣 什麼鬼事也不會發生(鬼月的話就不敢保證)

Attribute 只是掛好看的標籤 自然是需要冥冥之的股神秘力量額外的類別來看這些 Attribute 做對應的變化 才會有效果

聰明的看官想必也早知道謎底了 就是 ArticlesFactory 要來幹這件事(因為[工廠]就是要[黑箱]作業呀)

這裡就能看到 ArticlesFactory 透過神奇的演算法(?) 巧妙的過濾人名 改成OO

結果顯而易見 就是 Articles 被改成OO 沒啥好講的





現在就能明白什麼是[水平擴充]了

水平層面上的 [類別] 或 [方法] 都能任意的掛上 Attribute 來擴充功能

抽換 Attribute 都不會影響該 [類別] 或 [方法] 內部的運作

但是對於 外部(會來看這些 Attribute 的 [類別] 或 [方法])來說 又能 [提供不同等級的服務]





這貨很神呀 根本可以 單排上金 的感覺 沒有缺點嗎?





缺點自然是有的

使用 Attribute 難以偵錯 因為你可能不知道 到底是誰在使用這些 Attribute

像是這個範例 是由 ArticlesFactory 來使用 Attribute 做判斷

如果並不清楚 ArticlesFactory 會使用 Attribute 的情況下

得到的 Articles 就會不如預期

可能就無法得知 到底為什麼 人名變成 OO 了

明明 CODE (垂直) 裡面都沒有寫到這段功能

這個情況在 分別開發的時候 會更顯著





那什麼時候適合使用 Attribute 呢?

.NET MVC 就是很好的示範了

Authorize HttpPost AllowHtml OutputCache

這些不影響 Controller 內部邏輯的功能 就能抽出來變成 Attribute 交由第三方 (Framework) 完成實作





最後 Attribute 還有個屌炸天的應用

極度推薦!

2014年7月31日 星期四

你所不知道的 JS

開發時期:
  1. 撰寫 Javascrip 的時候
  2. 無法宣告型別
執行時期:
  1. Javascrip 在瀏覽器上運行的時候
  2. 會檢查型別
廣義物件:
  1. 所有東西都是物件(廣義)
  2. 物件是存放在記憶體中的資料
  3. 存在於執行時期
狹義物件:
  1. JavaScript 是由 Object 所組成。Array 是物件、Function 是物件、Objects 是物件。
  2. 在 JavaScript 的原生資料型態 (Primitive Data Type) 中,只有下列五種類型的「值」(value) 不被視為物件:
    1. Numbers 數值
    2. Strings 字串值
    3. Booleans 布林值
    4. null 空值
    5. undefined 未定義值
  3. 其它的所有東西,都算是物件的一種
物件:
  1. 物件只能靠變數屬性取用
  2. 物件是個容器,海納百川 有容乃大
  3. 物件是個雜湊陣列(HashMap)
  4. 物件只包含屬性 (Property) 方法 (Method or Function)
  5. 可以直接取得值的稱作屬性,可以執行的稱作方法
    1. var name = obj.name;
    2. obj.laughOutLoud();
型別:
  1. 分為原始型別物件型別
  2. 原始型別 number string boolean 有其對應的 原始型別包裹 Number String Boolean
  3. 不建議直接使用原始型別包裹
變數
  1. Javascrip 是動態語言 不需編譯就能執行
  2. 宣告變數用 var
  3. 全域變數區域變數兩種
  4. 除非有其非常必要性,否則盡量避免使用全域變數,避免互相影響跟衝突
  5. 建立變數的時候會同時建立屬性變數
    1. 在全域的時候會在根物件建立屬性,這會使得任何地方都能夠過跟物件的該屬性作存取
    2. 在區域的時候會在內部物件建立屬性,內部物件是個隱形人,你看不到也摸不到他,但是他確實存在
  6. 區域變數的作用域只以 function 區隔與一般 if for while 大括號範圍無關,故一個 function 內的所有變數都可能會互相影響跟衝突
  7. 要避免一個 function 內的變數互相影響跟衝突,除了注意命名之外,拆解成數個 function 會是較佳的做法
  8. 開發時期可以在任何位置使用 var 宣告變數,但是這些變數會在執行時期自動宣告在 function 內的頂端,他只會將變數名稱的宣告置頂(其值為 undefined),賦值的位置仍不變,這種特性稱為 Hoisting,這也是為何 function 內的變數不受大括號範圍影響的原因
  9. 小道消息指出,大多數人甚至開發 Javascrip 數十年的開發人員,都鮮少有人知道 Hoisting



2014年6月27日 星期五

LINQ 動態查詢 LINQKit PredicateBuilder + Glimpse 效能監測

早在 2013 LINQ 動態查詢 就困擾著我

http://weisnote.blogspot.tw/2013/03/dynamic-linq.html

當時找到 Dynamic LINQ

但是組字串並不是個好法子

(要組字串的話 我何不直接用 Pure T-SQL)





曾經與 LINQ 纏鬥過的朋友都知道 動態查詢 很難搞

尤其是 Or

並沒有什麼內建的法子 可以讓你動態來 Or Or Or

要不就寫死 .Where(x => x.Foo == 'Foo' || x.Bar == 'Bar || x.Goo == 'Goo' || x.Nar == 'Nar'')

要不就 Expression Trees 硬幹 像這樣

靠自己 好自在...才怪

賣鬧啊 Expression Trees 學習曲線 可沒比 Regular Expression 低 (雖然小弟兩樣都沒學好)





如今 2014 了 技術是會進步的!!

(其實應該出來滿久的 只是我沒去玩他)

拜讀於此:

援助教技--IT點滴日誌:http://neo-tech-tw.blogspot.tw/2013/08/linq-predicatebuilder.html

繼續沉睡5000年:http://leaflet-t-h.blogspot.tw/2011/11/linq-predicatebuilder.html

Kelp Code:http://kelp.phate.org/2011/12/linq-to-object-linqkitpredicatebuilder.html





鄭重歡迎 ~ LINQKit http://www.albahari.com/nutshell/linqkit.aspx





LINQKit 裡面應該是有不少妖魔鬼怪的 但是今天只來玩 PredicateBuilder 來搞定 Or Or Or

照官網範例 很簡單就 完成了

靠大神 好爽...正解





其中比較讓人困惑的 可能就是這句

var predicate = PredicateBuilder.False<Products>();

它的完整型別長這樣

Expression<Func<Products, bool>> predicate = PredicateBuilder.False<Products>();

更不懂了?? 其實他就下面這東東

Expression<Func<Products, bool>> predicate = x => false;

至於什麼時候用 PredicateBuilder.True<T> 什麼時候用 PredicateBuilder.False<T> 則是看接起來是什麼結果

簡單來說 如果都是 Or 用 PredicateBuilder.False<T> 如果都是 And 用 PredicateBuilder.True<T>





眼尖的考究帝一定有發現瀏覽器下面有一條鬼東西

那是最近神人傳授的好物 Glimpse

不僅美觀 功能更甚 MiniProfiler

Glimpse 官網http://getglimpse.com/Docs/

怎麼裝就不用講了 Nuget~催落去

真要說有什麼缺點的話 大概就是 螢幕太小很麻煩 因為 他內容很多 非常寬 : P

2014年6月22日 星期日

一秒看破 樞紐 查詢 SQL PIVOT UNPIVOT LINQ

什麼是樞紐?






......






DB

弄點假資料(手 KEY 就太傻太天真)

查出來這樣

但是 User 要這樣

硬幹吧 男孩 For~For~For~






多想兩分鐘,你可以不必自殺






官方有解 MS SQL 2005 + 都能玩

http://technet.microsoft.com/zh-tw/library/ms177410(v=sql.105).aspx

SELECT <非樞紐資料行>,

    [第一個樞紐資料行] AS <資料行名稱>,

    [第二個樞紐資料行] AS <資料行名稱>,

    ...

    [最後一個樞紐資料行] AS <資料行名稱>

FROM

    (<產生資料的 SELECT 查詢>)

    AS <來源查詢的別名>

PIVOT

(

    <彙總函式>(<要彙總的資料行>)

FOR

[<包含將變成資料行標頭之值的資料行>]

    IN ( [第一個樞紐資料行], [第二個樞紐資料行],

    ... [最後一個樞紐資料行])

) AS <樞紐分析表的別名>

<選擇性的 ORDER BY 子句>;






WTF...






看圖 (那堆 欄位沒法 直接用 SQL 搞 死心吧 只能靠 C# 組字串)

用 WITH 能略顯風騷???

沒了






等等...UNPIVOT 勒?






官網說 就是把 PIVOT 反過來






WTF...






有張反正規化的表

翻滾吧 Table

沒了






等等...LINQ 勒?






: P






http://abundantcode.com/how-to-create-pivot-data-using-linq-in-c/

http://linqlib.codeplex.com/wikipage?title=Pivot






2014年5月20日 星期二

ASP.NET Web Form 對應優先設計 (Mapping-First Design) 第三彈 - 被遺忘者

PM 常說 先求有 再求好

PG 就說 no problem!

於是三兩下搞定了 CRUD 交給 USER

然後立馬被玩壞

因為 USER 總是能夠超越極限 在 TextBox 裡面塞入無限的可能性

顯而易見 我們需要類似這種東東 防止 USER 的無限加速器全開

或許反射性的就想到工具箱裡面的好碰友...

but that was out of fashion





既然前面兩彈 大費周章的 弄了一個 values mapping system

又在每彈結尾留可有可無的伏筆

自然就是要在上面搞些花招

已達更加無腦的境界





首先從 Map 發想

我希望這樣子來使用欄位驗證

這裡由於驗證可能是複數 所以使用 ICollection

然後陣列可以當作 ICollection 的實體





再來就是 中二到不行的 抽象類 Judgement





之所以不想命名成 validation 之類的 只是因為不想跟 其他欄位驗證的類別混淆

並非因為這個傢伙

或這個傢伙





審判的細節 靠子類實作

至於實作的細節 平常怎麼幹 就怎麼幹囉

隨便貼一個





觸發審判的方式也沒什麼特別

就在 Buster 裡面挖個方法 觸發的時機 高興怎樣就怎樣囉

這邊是在 Buster 放個 IsAllInnocent 屬性 取得該屬性時 會觸發驗證

該死的 Click 事件 獲得了 欄位驗證 並且避免了 重度脂肪肝

Great Success





標題梗 again

2014年5月4日 星期日

ASP.NET Web Form 對應優先設計 (Mapping-First Design) 第二彈 - 百變星君

第一彈 之後 現在再來玩些變化

因為世上無可能有網頁 全部都只用 TextBox 的

在 CheckBox RadioButton DropDownList 參上之前 先來看看 先前第一彈 留下了什麼伏筆




1. 神手會失誤 庸手會失憶

每次都必須宣告 ValueMapBuster 變數 然後在 Page_Load 裡面 SetUpValueMaps Mapping 機制才會奏效

但是 神仙打鼓有時錯 每次都要 Key 這些固定 CODE 實在讓人 KEY 肚藍

所以我們需要 把這些給西 封裝起來 放到基底類裡面

再靠抽象方法 約束後人 必須實作 SetUpValueMaps





2. 噁心的 人形蜈蚣 代碼

什麼是 人形蜈蚣 代碼?

something like...

or like...

咦 好像沒什麼不對呀?

這樣寫的確 沒有任何錯誤 程式依舊能跑

但是這是一個造成 難以維護的 壞味道

如果哪天 條件增加 減少了 勢必要到處去修改這些蜈蚣

況且 這麼多的判斷式 如果只是為了 "其中一種狀況" 發生的時候該做什麼 "對應的事" 的話

其他的 判斷式 在這裡就顯得有點擋路

所以我們需要 善用多型

首先把原本的 ValueMap<T> 變成抽象類


GetValue 和 SetValue 則依靠 抽象方法實作 GetDefaultValue 和 SetDefaultValue 的細節 (就是原本蜈蚣的部分)


再來就是 "多型" 的部分 原先 Mapping 的時候 需要考慮各種控制項的可能

現在則是每種控制項 增加一個獨立的類別 並且繼承 ValueMap<T> 來實作細節

這裡 又會遇到一項設計上的考量 有時候 某個值不見得只靠一種控制項 就能表現

最顯而易見的就是 RadioButton

一群的 RadioButton 實際上只對應某個欄位的列舉值

所以分成 單體 跟 群組 兩種類型的 Map 來應付

單體

TextBoxMap:預設 Map Text 屬性


DropDownListMap:預設 Map SelectedValue 屬性


CheckBoxMap:預設 Map Checked 屬性


HiddenFieldMap:預設 Map Value 屬性


群組

GroupMap:由於是複數控制項表示一欄位值 所以必須要 自行設定 OnGetValue 跟 OnSetValue


CheckGroupMap:專門處裡 RadioButton 或 CheckBox 群組 預設 Map Checked 屬性





上面改了一堆 實際上究竟如何呢? 馬上來把之前的一堆 TextBox 改成 百變星君

首先改 UI 恕我不貼 HTML -.-...


再來當然是...超超超長 Map

呼...好累...然後呢?

什麼然後? * w * ??? 沒有然後了呀

沒錯 Mapping-First 在 Map 完了之後 大半就完成了

除了 SQL 多了些欄位之外 Click 事件內的 Code 無須更動



難道這是傳中的 Two-Way Data Binding!! (誤)




咦?如果我 TextBox 亂打 不合型別會怎樣?

呵呵呵 當然是會壞掉呀 因為現在還沒 實作欄位驗證

敬待 下回分曉 ˊ_>ˋ




Déjà vu?????????????




標題梗: