在這篇文章裡,我們來針對一些問題進行討論。如果您覺得有哪些您感興趣但是沒有涉及 到的問題則請在評論中補充,我會修改文章添加一下內容。陷阱何在?
首先,我們來分析上一篇文章最後談到的“陷阱”。很可惜啊,過了兩個星期還是沒有朋 友能夠指出這個問題,其實很簡單,運行一下就能發覺有異常拋出:
public partial class Default : System.Web.UI.Page, IForbiddenWordFilter
{
...
FilterForbiddenWordType IForbiddenWordFilter.GetFilterType(string key)
{
if (key.EndsWith(this.txtPassword.ID)) return FilterForbiddenWordType.Ignored;
return FilterForbiddenWordType.Normal;
}
}
在運行至this.txtPassword.ID時會拋出NullReferenceException。其原因就是,我們的 FilterForbiddenWordModule在OnPostMapRequestHandler過程中進行調用,而此時Handler對 象已經生成(意味著IForbiddenWordFilter.GetFilterType方法已經可以調用),但是直到 Handler被執行時this.txtPassword才被實例化(從現象得出的結論,是否確切有待考證), 自然會拋出NullReferenceException了。可是我實在想不出一個辦法可以在得到 this.txtPassword.ID的值,甚至退一步講,我無法在運行時得到this.txtPassword這個 field的名稱——即一個字符串“txtPassword”。我不可能直接使用這個字符串常量,這樣 就會使我們的改進效果付之東流。我們需要通過代碼來訪問,因為我們需要能夠得到編譯及 重構的支持,不是嗎?
起初我很絕望,但是10分鐘後忽然靈光一閃,想到了這種方式來獲得field的名稱:
FilterForbiddenWordType IForbiddenWordFilter.GetFilterType(string key)
{
Expression<Func<object>> action = () => this.txtPassword;
var name = (action.Body as MemberExpression).Member.Name;
if (key.EndsWith(name)) return FilterForbiddenWordType.Ignored;
return FilterForbiddenWordType.Normal;
}
這是一個非常實用的技巧:通過Lambda表達式來構造一個表達式樹,然後通過這個表達式 樹的成員來獲取field的名稱。我們享受到了我們所需的便利,因為個中實現已經由編譯器完 成(或許我會另寫文章來闡述一下我在關於這個方面的思維過程)。
適用場合
有的時候我覺得談適用場合比較虛,因為其實關鍵是在“思考”。“官方”提出的適用場 合並不一定完整和正確,了解了一個解決方案之後慢慢會有更好的體會,甚至更真實。如果 一個解決方案是通過一個適用場合引發的,那麼這個解決方案的適用場合“似乎”不言而喻 。此外,如果一個解決方案是像我們現在的這樣一樣,從實際出發,再發散,慢慢將功能補 充完整,最後幾經權衡之後反而有些違背初衷,那麼談適用場合其實就是在談“理解”,當 你理解了這個解決方案的特性,適用場合和不適用場合都可以簡單地判斷出來。所以再虛還 是要談,至少要擺個樣子思考一下。
例如:我們是在輸入的時候進行過濾,那麼服務器端得到的數據已經是替換後的內容,因 此如果你要用戶原本輸入的內容,肯定就不能采用這個方法。
嗯?完了?當然沒完,但是下面就要由您來進行思考了。:)