2010-02-19 305 views
6

我有一個像Dictionary(TKey, TValue)匿名類型

Dictionary<int, ArrayList> Deduction_Employees = 
    new Dictionary<int, ArrayList>(); 

,後來我添加到數組列表中的一個匿名類型喜歡這個

var day_and_type = new { 
    TheDay = myDay, 
    EntranceOrExit = isEntranceDelay 
}; 

Deduction_Employees[Employee_ID].Add(day_and_type); 

現在我怎樣才能拆箱是var和訪問這些屬性?

+4

最大的問題是你爲什麼想要?你想達到什麼目的? – pdr

回答

13

首先,你不拆箱的類型。匿名類型是引用類型,而不是結構。

即使技術上可以創建他們在被宣佈的方法之外的相同類型的實例(如每節的C#3.0語言規範,其中規定7.5.10.6:

在同一個程序,兩個匿名 對象初始化指定同一 名稱的屬性的 序列和 相同的順序將產生的 相同匿名類型實例編譯時間類型。

)您無法獲得該類型的名稱,您需要將其從Object轉換回您創建的類型。你將不得不求助於本質上有缺陷的cast-by-example solution

由於從設計的角度來看,Cast-by-Example存在缺陷,您希望在聲明的函數外部訪問該類型的每個位置(並且仍位於同一模塊內),因此必須全面有效地聲明類型再次。

這是一次重複的努力,導致了sl design的設計和實施。

如果您使用的是.NET 4.0,那麼您的可能將放置在一個動態變量中。但是,主要的缺點是缺少成員訪問的編譯時驗證。你可能很容易拼錯成員的名字,然後你有運行時錯誤而不是編譯時錯誤。

最終,如果您發現需要在聲明的方法之外使用匿名類型,那麼唯一的好方法是創建一個具體類型並用匿名類型替代具體類型。

1

不,你不能。您只能使用反射訪問屬性。編譯器無法知道類型是什麼,並且由於它是匿名類型,因此無法將其轉換。

1

如果您使用的是.NET 1.x - 3.x,則必須使用反射。

如果您使用.NET 4.0,則可以使用動態類型並調用期望的屬性。

在這兩種情況下你都不需要unbox;這是價值類型。匿名類型始終是引用類型。

3

一個匿名類型有方法範圍。要在方法邊界外傳遞匿名類型或包含匿名類型的集合,必須先將類型轉換爲對象。但是,這打破了匿名類型的強類型。如果您必須存儲查詢結果或將其傳遞到方法邊界之外,請考慮使用普通的命名結構或類而不是匿名類型。

來源:http://msdn.microsoft.com/en-us/library/bb397696.aspx

8

有幾種方法。

由於評論似乎表明我建議你這樣做,所以讓我說清楚:你應該爲你的對象創建一個命名類型,因爲你打算傳遞它。

首先,您可以使用反射,這裏的另一個答案已經指出。

另一種方法,它讓技術.NET給你正確的類型被稱爲「按例轉換」,它是這樣的:你需要通過一個通用的方法調用傳遞你的對象,這將返回對象作爲正確的類型,通過推斷正確的類型返回。

例如,試試這個:

private static T CastByExample<T>(T example, object value) 
{ 
    return (T)value; 
} 

,並使用它:

var x = CastByExample(new { TheDay = ??, EntranceOrExit = ?? }, obj); 

兩個?點,你只需要傳遞適合這些屬性的數據類型的東西,這些值就不會被使用。

這利用了這樣一個事實,即在同一個程序集中,包含相同順序的完全相同屬性的多個匿名類型將映射到相同的單一類型。

但是,到目前爲止,您應該創建一個指定類型。

+0

+1剛纔看到對msdn的評論以及如何利用它 - 「如果兩個或多個匿名類型具有相同順序的相同數量和類型的屬性,編譯器將它們視爲相同類型,並且它們共享相同的編譯器生成的類型信息「。 – Kobi

+0

@Lasse V. Karlsen:最終,以身作則是一個諷刺。您有效地在您希望訪問的模塊中的方法之外的每個地方重新聲明該類型,違反了重用的基本原則。 – casperOne

+0

非常好,但感覺很尷尬。幾乎是邪惡:) –