我們說Anonymous Type是C# 3.0的新的特性,而沒有說Anonymous Type 是.NET Framework 3.5的新特性。這是因為Anonymous Type僅僅是.NET Programming Language和相應的Compiler的新引入的特征。而對於.NET Framework 3.5來說,它看不到這和原來有什麼不同,對於Anonymous Type和一 般的Named Type,對於CLR來說他們之間沒有什麼本質的區別。
通過下面這樣的一段簡單的代碼:
1var p1 = new { Name = "IORI", Age = 27 };
然後我們再看看IL:
Code
1.method private hidebysig static void Main(string[] args) cil managed
2{
3 .entrypoint
4 // Code size 15 (0xf)
5 .maxstack 3
6 .locals init ([0] class '<>f__AnonymousType0`2'<string,int32> p1)
7 IL_0000: nop
8 IL_0001: ldstr "IORI"
9 IL_0006: ldc.i4.s 27
10 IL_0008: newobj instance void class '<>f__AnonymousType0`2'<string,int32>::.ctor(!0,
11 !1)
12 IL_000d: stloc.0
13 IL_000e: ret
14} // end of method Program::Main
15
我們再這裡就可以看出Compiler將會為p1這個Anonymous Type創建一個名為 <>f__AnonymousType0`2<string,int32>的類型。參數將根據數據 成員的具體結構,這裡也是聲明一個類型。這個類繼承自object,並且重寫了 ToString() 和 GetHashCode()的實現。所有的匿名類型自動繼承自 System.Object ,並且重寫了Equals(), GetHashCode(), and ToString(). 如 下圖:
結構如下:
internal sealed class <>f__AnonymousType0<<Name>j__TPar, <Age>j__TPar>
{
// Fields
private readonly <Age>j__TPar <Age>i__Field;
private readonly <Name>j__TPar <Name>i__Field;
// Methods
public <>f__AnonymousType0 (<Name>j__TPar Name, <Age>j__TPar Age);
public override bool Equals(object value);
public override int GetHashCode();
public override string ToString();
// Properties
public <Age>j__TPar Age { get; }
public <Name>j__TPar Name { get; }
}
再看看下面的例子。
Code
1class Program
2 {
3 static void Main(string[] args)
4 {
5 var p1 = new { Name = "IORI", Age = 27 };
6 var p2 = new { Name = "IORI", Age = 27 };
7 var p3 = new { Name = "GUOJUN", Age = 27 };
8 var p4 = new person { Name = "GUOJUN", Age = 27 };
9 Console.WriteLine("Base class of {0} is {1}", p1.GetType().Name, p1.GetType().BaseType);
10 Console.WriteLine("p1.ToString() = {0}", p1.ToString());
11 Console.WriteLine("p1.GetType() = {0}", p1.GetType());
12 Console.WriteLine("p3.GetType() = {0}", p3.GetType());
13 Console.WriteLine ("p4.GetType() = {0}", p4.GetType());
14 Console.WriteLine("p1.GetHashCode() = {0}", p1.GetHashCode ());
15 Console.WriteLine("(p1.GetHashCode() == p2.GetHashCode())= {0}", p1.GetHashCode() == p2.GetHashCode ());
16 Console.WriteLine("(p1.GetHashCode() == p3.GetHashCode())= {0}", p1.GetHashCode() == p3.GetHashCode ());
17 Console.WriteLine("p1.Equals(p2)= {0} ", p1.Equals(p2));
18 Console.WriteLine ("p1.Equals(p3)= {0}", p1.Equals(p3));
19 Console.WriteLine("p3.Equals(p4)= {0}", p3.Equals(p4));
20 Console.WriteLine("(p1 == p2)= {0}", p1 == p2);
21 Console.WriteLine ("object.ReferenceEquals(p1.GetType(),p2.GetType()) = {0}", object.ReferenceEquals(p1.GetType(), p2.GetType()));
22 Console.WriteLine("object.ReferenceEquals(p1.GetType (),p3.GetType()) = {0}", object.ReferenceEquals(p1.GetType(), p3.GetType()));
23 Console.WriteLine ("object.ReferenceEquals(p3.GetType(),p4.GetType()) = {0}", object.ReferenceEquals(p3.GetType(), p4.GetType()));
24 Console.Read();
25 }
26 }
27
28 class person
29 {
30 public int Age {get;set;}
31 public string Name {get; set;}
32 }
33
我們看看輸出的結果。
通過以上的結果我們更能對Compiler會為Anonymous Type創建的類型 更好的理解。
GetHashCode() 實現時,根據匿名類型的每個成員作為 System.Collections.Generic.EqualityComparer<T>的輸入,來計算hash 值。因此,如果2個匿名類型有相同的屬性字段,同時每個字段的值也相同,那 麼生成的Hash值也就相等。
ToString() 只是簡單的用 屬性名稱/屬性 值 構造了一個字符串。
Equals() 結果相等,因為它使用值來比較 相等。
== 結果不等,因為匿名類型沒有重載 == 和 != , 這兩個操作符默認情況下,比較的是對象的引用而不是值。
總結:
• Anonymous types繼承 System.Object.
• The fields and properties 是read-only.
• Anonymous types 不支持 events, custom methods, custom operators, or custom overrides.
• Anonymous types 是個密封類.
• Anonymous types 用自己定義的構造方法(不可以修改)來創建的.
最重 要的是
Compiler在生成Anonymous types 的時候,並不是為每個如{N=?, N2 =? , ...}的結構生成一個不同的Type,它只會為不同的參數列表的結構:參 數的名稱,參數的數據類型,參數的相互順序定義不同的Type(不包含參數的值) 。而具有相同的參數列表的{N=?, N2 =? , ...}會共享同一個Type。但是這種僅 限於在同一個Assembly中,編譯器只會生成一個匿名類型,這些對象都是該唯一 的匿名類型的實例。