使用 dynamic 傳回匿名型別的 IEnumerable 集合

乍看有點奇妙的型別 IEnumerable<dynamic>,可以用來傳回匿名型別的 IEnumerable 集合,還蠻方便的。

舉例來說,我在 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 語法還藏有不少有趣的東西哩!

沒有留言:

技術提供:Blogger.
回頂端⬆️