none
如何傳遞匿名型別給User Control對外的屬性 RRS feed

  • 問題

  • 大家好:
        最近使用改用LINQ to Entity存取資料庫,但是遇到一個問題不知道該怎麼寫,請問大家如何把LINQ查詢結果的匿名型別,傳給User Control對外的屬性呢?
    例如我想將北風資料庫的Region資料表查詢出來的結果傳給User Control對外的屬性,該用什麼資料型態承接呢?


    .NET Framework:3.5
    OS:Windows XP Sp3
    IDE: VS 2008

    using (NorthwindEntities context = new NorthwindEntities())
           {
               ObjectQuery<Region> region = context.Region;
               var result = from p in region
                               select p;
           }
    
    • 已編輯 TerryChuang 2009年8月4日 上午 09:03
    • 已移動 Lolota Lee 2009年8月4日 上午 09:31 LINQ related (從:Visual C#)
    2009年8月4日 上午 09:01

解答

所有回覆

  • Hi,

    你可以把滑鼠移到Var還是result上

    IDE會提示目前的型態

    http://www.dotblogs.com.tw/larrynung/
    2009年8月4日 上午 09:22
  • 沒辦法. Var 只適用在Method 裡.超過這個範圍,他就無法推斷他的型別了.
    2009年8月4日 上午 09:25
  • Hi,

    請參考

    一般來說Linq是會用變數型別去接
    但其實回傳的是IEnumerable<T>

    http://www.dotblogs.com.tw/larrynung/
    2009年8月4日 上午 09:36
  • 你已知道是Region型別了,你就這個強型別去傳

    2009年8月4日 上午 09:37
  • 感謝各位熱心的回覆,可能我的例子舉的不好,因為我遇到的是多個TABLE的查詢結果,不知道怎麼傳遞,我的程式片段大致如下:
    ObjectQuery<Customers> customer = context.Customers;
    ObjectQuery<Orders> order = context.Orders;
    var query = from p in customer
                      join q in order
                      on p.CustomerID equals q.Customers.CustomerID
                      select new { p.CustomerID, p.CompanyName, q.OrderID, q.OrderDate };
     foreach (var q in query)
    {
      Response.Write(q.CustomerID + "," + q.CompanyName + "," + q.OrderID + "," + q.OrderDate + "<br/>");
      Response.Write(q.GetType());
    }
    上述程式得到下列的匿名型別。
    <>f__AnonymousType0`4[System.String,System.String,System.Int32,System.Nullable`1[System.DateTime]]

    2009年8月4日 上午 09:44
  • Hi,

    如果是像你這例子

    就不行了

    參考下文 文中有提到"匿名型別的物件也不能當作參數傳遞"

    http://www.dotblogs.com.tw/larrynung/
    • 已標示為解答 TerryChuang 2009年8月4日 上午 10:03
    2009年8月4日 上午 09:59
  • 看來我得改變我的做法,不過我會想這樣做是因為想要把LINQ的查詢結果重複使用,不曉得哪位先進可以分享一下,您(們)的經驗呢,謝謝。
    2009年8月4日 上午 10:03
  • 我用Var的情形:
    1.有時偷懶少打幾個字,但大部分我還是喜歡強型別,不喜歡這種推測的型別.
    2.Var在這個方法裡,已可以預測其結果,且結果在這方法裡要處理掉.比如說Binding到UI.
    3.在Linq裡非常好用,比如說要組一群的條件.但這一群條件我無法預知哪幾個條件組合用到.就用 Var 去++++條件.最後用 foreach 或 ToList()去傳回強型別結果.
    4.最後你可能不知最終結果下,你就要用OO多型方式去做直傳遞轉換...處理.

    2009年8月4日 上午 10:19
  • 謝謝好說的分享。
    2009年8月4日 上午 10:22
  • Hi,

    C# 4.0後支援Dynamic Lookup
    看起來可以達到你的需求
    不過還在Beta~你可以稍微關注一下

    http://www.dotblogs.com.tw/larrynung/
    2009年8月5日 上午 01:06
  • 蹂躪 兄,等待你 4.0的使用心得.
    我記得 .net 1.x-3.5 每次出新功能,MSDN都會放很多文章.那時訂RSS有時一天就有好幾十篇.不知是RSS換了,還是MS文章變少了.
    以前新版本還沒Release時我就已經懂怎麼用了.我的系統也準備更新.
    但現在,文章好了 .net 4.0 感覺不知有什麼用,尤其 Dynamic Lookup 到底在做什麼?
    所以等待你的研究.
    2009年8月5日 上午 01:47
  • 可行的
    研究一下C# 4.0 的Dynamic做法就會找出解決方式,其實很簡單就是透過Reflection.
    C# 4.0的Dynamic本身並未修改CLR而是如LINQ一樣只是擴充IDE與編譯器功能,底層的實作是以現有的Reflection技術來達成

    所以你的問題可以如下解決.只是使用上不像Dynamic那麼直覺,但可以自行撰寫class簡化封裝取值過程

        class Program
        {
            static void Main(string[] args)
            {
                foreach (object item in Test())
                {
                    Type t = item.GetType();                
                    foreach (PropertyInfo pi in t.GetProperties ())                
                   {
                           object o = pi.GetValue(item, null);
                    }                        
                }
    
                Console.Read();
            }
    
            static IEnumerable<object> Test()
            {
                string[] sa = new string[] { "aaa", "bbb", "ccc", "ddd" };
                var q = sa.Where(s => s.Length == 3).Select(s => new { s.Length, s });
    
                return q.Cast<object>();
            }
        }
    • 已編輯 programlin 2009年8月5日 上午 02:25
    2009年8月5日 上午 02:13
  • to Programlin 你的範例好像沒用到Dymanic 吧? 你不是只傳 IEnumerable<object>.
    整個程式的重點還是在//這邊透過Reflection機制取得匿名型別的欄位.
    也就在將object DownCast 回到原型別.
    你有沒有 //這邊透過Reflection機制取得匿名型別的欄位.
    這段用 Dymanic 去反轉的Code.
    2009年8月5日 上午 02:28
  • 剛剛已補上
    另外如果要取得特定欄位
    譬如我例子中的
    new{s.Lenght,s}
    產生的匿名型別雖然Class名稱非固定,但屬性名稱卻是固定的
    以上面的例子就是Length與s
    或是強制產生需要的屬性名稱
    new{a=s.Lenght,b=s}

    而在取值過程中可以使用
    pi.Name來判斷是否是你要取值的欄位.
    • 已編輯 programlin 2009年8月5日 上午 02:33
    2009年8月5日 上午 02:29
  • 這是一般的Reflection解法.
    2009年8月5日 上午 02:32
  • >>這是一般的Reflection解法.
    沒錯

    Dynamic本身也是這樣做.只是他封裝了取值過程讓程式看起來比較直覺而以

    dynamic a = new {filed1 = "aaa",  filed2 = 1};
    fun(a);

    void fun(dynamic  d)
    {
    string a = d.filed1;
    int b = d.filed2;
    }

    以上為dynamic 的範例Code
    如果使用過VS2010編輯此Code時會發現第二段的string a = d.filed1;當你打d時並不會列出有哪些屬性跟方法.
    所以實際上d.filed1這個只是在編譯時期編譯成對應的Reflection相關程式碼,在RunTime時如果d沒有filed1則會出現runtime error


    所以如果你用
    int i = 3;
    呼叫
    fun(i);

    編譯器是可以通過的,但執行時期一定會error,這也就是dynamic的用途.

    dynamic在某些情況能達成strong type所無法達成的方便性,但dynamic不能拿來濫用就如匿名型別的var是一樣的.

    2009年8月5日 上午 02:41
  • 嗯~反射可以做到
        class Program
        {
            static void Main(string[] args)
            {
                foreach (object item in Test())
                {
                    Console.WriteLine("Length:" + GetNickClassValue(item, "Length"));
                    Console.WriteLine("S:" + GetNickClassValue(item, "s"));
                }
    
                Console.Read();
            }
    
            static object GetNickClassValue(object obj,string propertyName)
            {
                Type t = obj.GetType();
                PropertyInfo pi = t.GetProperty(propertyName);
                return pi.GetValue(obj, null);
            }
    
            static IEnumerable<object> Test()
            {
                string[] sa = new string[] { "aaa", "bbb", "ccc", "ddd" };
                var q = sa.Where(s => s.Length == 3).Select(s => new { s.Length, s });
    
                return q.Cast<object>();
            }
        }
    Dynamic底層也是用反射
    但是有點麻煩
    若沒寫成函式庫重覆套用
    應該還是直接改寫成具名型別來得方便
    不過要在類別中常要用來傳來傳去的資料用匿名型別
    好像非匿名型別本來的用意

    http://www.dotblogs.com.tw/larrynung/
    2009年8月5日 上午 02:53
  • 說真的我還是看不懂Dynamic的用法!
    我這裡所謂看不懂,不是範例看不懂,也不是語意,文章看不懂.
    而是這個東西要用在哪裡?
    一般來說,Programmer 都已經可預知是什麼型別,什麼結果了.
    在什麼時候需要 Run Time 才跑出來的形態?
    你把編譯時期的錯誤偵測延遲到Run Time 反而比較難開發跟除錯.
    另外Dynamic 也Disable掉很多 VS 智慧開發的提示的功能.反而會使字打錯.

    2009年8月5日 上午 03:16
  • Hi,

    保哥文章中有提到幾個用的上的地方

    http://blog.miniasp.com/?tag=/c%23+4.0

    C# 4.0 新特性:動態型別、選用參數、具名參數

    在 New Features in C# 4.0 文件中提到了四個可善用動態特性的例子:

    • 從動態語言來的動態物件存取,例如:Python 或 Ruby 等
    • 透過 IDispatch 存取 COM 物件
    • 原本透過 Reflection (反映) 存取 .NET 型別的方式將可透過 dynamic 型別簡化操作
    • 處理會不斷改變結構的物件,例如:HTML DOM 物件

    另外若有用過VB.NET晚期繫結

    或是用過CreateObject去做Office操作

    可能會比較有感覺

    http://www.dotblogs.com.tw/larrynung/
    2009年8月5日 上午 03:28
  • •從動態語言來的動態物件存取,例如:Python 或 Ruby 等 •透過 IDispatch 存取 COM 物件 •原本透過 Reflection (反映) 存取 .NET 型別的方式將可透過 dynamic 型別簡化操作 •處理會不斷改變結構的物件,例如:HTML DOM 物件 Dynamic 好像是.net 4.0 最重要的功能.其他什麼像VB 方法減少傳遞參數的方法...感覺對寫程式好像影響不大. 就上面4個特性. 1.坦白說Python,Ruby是什麼?你一開始就決定用MS方案,用C#或VB語言.知道它們的特性了.哪時候你會去學Python,Ruby哪? 2.用COM,COM的特性大家都會用了.使用前也都查過使用文件了,好用Dynamic也不需要. 3.我連Reflection都沒用過,我只用Reflection工具破解過二支專業元件過(一支是繪圖元件,一支是通訊元件).版上有人在使用Reflection?有沒有使用心得. 4.實在很抽象,不斷改變結構的物件?是用來破解電動玩具嗎?HTML DOM會不斷變動?
    2009年8月5日 上午 03:42
  • To 好說:
    其實這個問題就如同當初JAVA陣營一開始很反對將泛型納入JAVA Runtime內.因為會增加語言的複雜度,且泛型不是個非必要的選擇,透過一些程式技巧一樣能做到所要達成的目的.
    但後來還是妥協了,一部分是因為dotNet納入,另一個原因是方便性.

    而Dynamic也是這個原因,Dynamic最重要的兩個原因就是
    1.CLS動態語言的支持需要(在此強調我本人從以前到現在就很不認同dotNet可以支持多語言這個特性,說穿了只是噱頭)
    2.簡化Reflection,這是我認為最重要的原因,Reflection這樣技術我相信很多人在某些情況下都會使用,在dotNet運作中有太多需要Reflection相關技術,但目前Reflection的API操作起來很繁雜,Dynamic可以簡化此操作

    而象存取COM,HTML DOM等特性都只是上訴的第二點衍生,這些東西全都可以靠Reflection達成,但不可否認的使用上太麻煩.

    如同現階段如果要對一個集合型別做操作,有了LINQ哪個人不用?

    但Dynamic與Var推斷型別相同很容易被濫用,自從var出現後我發現很多範例文章開始使用var來取代所有的強行別,這是個非常不好的習慣.
    很有可能當dynamic普及後很多人開始把dynamic當作參數引數做為function間傳遞的型態,開始濫用dynamic,甚至可能衍生出多人開發時,大家公認的傳輸資料型態就是dynamic這種狀況.
    2009年8月5日 上午 03:45
  • 謝謝 Programlin的解說. 的確東西不能亂用. 等 .NET 4.x 更多文章,更多範例後再來研究導不導.
    2009年8月5日 上午 03:50