寫 ASP.NET MVC CSHTML 時,我很習慣用 ViewBag 將變數從 Controller 傳到 View 端,只是簡單傳遞幾個字串、數值,為此大費周章宣告 Model 型別有點殺雞用牛刀。我們都知道 ViewBag 是一個 dynamic 型別,而 dynamic 型別的屬性、方法也會被視為 dynamic,編譯階段不檢查,執行階段見真章。
不過,最近學到一件事:一旦函式參數傳入 dynamic,其傳回值也會被視為 dynamic,而此時將無法使用 Lambda 運算式。
來看下面這個例子。我計算透過 ViewBag.DateString 傳遞 "2017/08/26"格式字串 View,在 CSHTML 裡我用變數 dateStr 接入此字串,試著查 Length,跑 Split('/').First() 都沒問題。再來我寫了一個簡單函式 - MySplit,輸入 string,傳回 Split('/') 後的 string[]。將 dateStr 當參數傳入 MySpit,取傳回 string[] 的 Length OK,但想對 string[] 做 Any(o => o.Length > 3) 卻產生錯誤:
Error CS1977 Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type. 無法將 Lambda 運算式當做動態分派作業的引數,而未先將它轉型為委派或運算式樹狀架構型別
![](http://www.darkthread.net/Photos/4154-c7f6-o.gif)
依照錯誤訊息指示,(string[])MySplit(dateStr) 將其強轉型後問題即告排除。至此我才發現,原來不只 dynamic 的屬性會被視為 dynamic,連一般的函式方法,只要傳入 dynamic 傳回結果也會被視為 dynamic。這應該跟參數有 dynamic 時 .NET 會改用複雜機制動態觸發函式有關,詳情可參考前文:方法多載(Method Overloading)與 dynamic 。
我們用 DateTime.ParseExact 測試,傳入 dateStr,在傳回的 DateTime 上寫 DarkthreadYear 都可以編輯成功(當然,執行階段必爆無夷),而由 Visual Studio 的顯示也可確認它被視為 dynamic。
![](http://www.darkthread.net/Photos/4156-c57b-o.gif)
而在這個案例中,更簡單的解法是將 var dateStr 改成 string dateStr,多打兩個字元,問題消失殆盡!
![](http://www.darkthread.net/Photos/4155-f84f-o.gif)
了解到這個特性,我決定養成一個習慣,不再用 var 宣告變數承接 ViewBag 傳遞過來的資料,而要明確宣告變數型別。如此在編輯階段可全程享受 Visual Studio 的強型別檢查與 Intellisense 支援,也避免衍生 Lambda 運算式碰壁的困擾,而依據先前研究,參數為 dynamic 時,.NET 將改用較複雜的動態機制處理函式呼叫,使用強型別也將有助於提高效能,一舉多得,何樂不為?