乍看有點奇妙的型別 IEnumerable<dynamic>,可以用來傳回匿名型別的 IEnumerable 集合,還蠻方便的。
舉例來說,我在 ASP.NET 網頁上用一個 GridView 來顯示查詢結果(可分頁、可排序)。此 GridView 繫結至一個 ObjectDataSource:
如上述標籤所示,此 ObjectDataSource 物件會使用 MyDemo.Web.CustomerPage 類別的 GetCustomers 方法來取得客戶資料。這個 GetCustomers 方法大概長這樣:
此方法的回傳型別是 IEnumerable<Models.Customer>,而且查詢結果包含 Customer 資料表的全部欄位。程式可以順利編譯、執行。
可是,如果資料表的欄位數量太多,希望改為僅選取部分欄位,而且不想定義新的 view model 類別,則原先的 LINQ 查詢敘述可能會改成:
此時的變數 qry 的型別就成了匿名的 IQueryable 集合,亦即 IQueryable<只有編譯器知道的型別>。
問題來了:既是匿名的泛型集合,此方法的回傳型別該怎麼寫呢?
試過幾種寫法,不是無法通過編譯就是執行時發生錯誤,例如轉型失敗、物件不支援分頁之類等等,最後是用 IEnumerable<dynamic> 來解決:
最後的 return 敘述,在呼叫 ToList 方法時也可以明白寫成 ToList<dynamic>()。
C# 4 的 dynamic 語法還藏有不少有趣的東西哩!
舉例來說,我在 ASP.NET 網頁上用一個 GridView 來顯示查詢結果(可分頁、可排序)。此 GridView 繫結至一個 ObjectDataSource:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="GetCustomers" TypeName="MyDemo.Web.CustomerPage" > </asp:ObjectDataSource>
如上述標籤所示,此 ObjectDataSource 物件會使用 MyDemo.Web.CustomerPage 類別的 GetCustomers 方法來取得客戶資料。這個 GetCustomers 方法大概長這樣:
public IEnumerable<Models.Customer> GetCustomers() { using (var db = new Models.NorthwindContext()) { var qry = from c in db.Customer select c; return qry .OrderByDescending(c => c.ID) .ToList(); } }
此方法的回傳型別是 IEnumerable<Models.Customer>,而且查詢結果包含 Customer 資料表的全部欄位。程式可以順利編譯、執行。
可是,如果資料表的欄位數量太多,希望改為僅選取部分欄位,而且不想定義新的 view model 類別,則原先的 LINQ 查詢敘述可能會改成:
var qry = from c in db.Customer select new { ID, CompanyName, };
此時的變數 qry 的型別就成了匿名的 IQueryable 集合,亦即 IQueryable<只有編譯器知道的型別>。
問題來了:既是匿名的泛型集合,此方法的回傳型別該怎麼寫呢?
試過幾種寫法,不是無法通過編譯就是執行時發生錯誤,例如轉型失敗、物件不支援分頁之類等等,最後是用 IEnumerable<dynamic> 來解決:
public IEnumerable<dynamic> GetCustomers() { using (var db = new Models.NorthwindContext()) { var qry = from c in db.Customer select new { ID, CompanyName, }; return qry .OrderByDescending(c => c.ID) .ToList(); } }
最後的 return 敘述,在呼叫 ToList 方法時也可以明白寫成 ToList<dynamic>()。
C# 4 的 dynamic 語法還藏有不少有趣的東西哩!
沒有留言: