匿名类
匿名类就一个没有名称的类,它同样继承自Object。匿名类通常和var、new一起使用,例如,我们需要定义一个对象,该对象中包含姓名、年龄、性别3个字段:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var person = new { Name = "CS", Age = 20, Gender = true }; 6 Console.WriteLine(person.GetType().Name);//<>f__AnonymousType0`3 7 8 Console.ReadKey(); 9 } 10 }
我们通过ILDasm反编译程序集,通过IL代码看一下匿名类的真面目:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代码大小 39 (0x27) .maxstack 3 .locals init ([0] class '<>f__AnonymousType0`3'<string,int32,bool> person) IL_0000: nop IL_0001: ldstr "CS" IL_0006: ldc.i4.s 20 IL_0008: ldc.i4.1 IL_0009: newobj instance void class '<>f__AnonymousType0`3'<string,int32,bool>::.ctor(!0, !1, !2) IL_000e: stloc.0 IL_000f: ldloc.0 IL_0010: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() IL_0015: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() IL_001a: call void [mscorlib]System.Console::WriteLine(string) IL_001f: nop IL_0020: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() IL_0025: pop IL_0026: ret } // end of method Program::Main
从IL代码可以看出来,person对象实际上是泛型类<>f__AnonymousType0`3的一个对象,Console.WriteLine(person.GetType().Name);也对其进行了验证,也就是说匿名类的本质是一个泛型类,并且匿名类的属性是只读的。
匿名类可以用于在线程间传递数据,因为它的属性是只读的。
我们在看下面的代码:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var person1 = new { Name = "CS", Age = 20, Gender = true }; 6 var person2 = new { Name = "CS", Age = 23, Gender = false }; 7 var person3 = new { Age = 20, Name = "CS", Gender = true }; 8 var person4 = new { Name = "CS", Age = 20, Gender = "男" }; 9 var person5 = new { Name = "CS", Age = 20, Gender = true, Address = "HN" }; 10 Console.WriteLine(person1.GetType() == person2.GetType());//True 11 Console.WriteLine(person1.GetType() == person3.GetType());//False 12 Console.WriteLine(person1.GetType() == person4.GetType());//False 13 Console.WriteLine(person1.GetType() == person5.GetType());//False 14 15 Console.ReadKey(); 16 } 17 }
我们同样通过IL代码来看一下,编译器为我们做了哪些工作:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代码大小 181 (0xb5) .maxstack 4 .locals init ([0] class '<>f__AnonymousType0`3'<string,int32,bool> person1, [1] class '<>f__AnonymousType0`3'<string,int32,bool> person2, [2] class '<>f__AnonymousType1`3'<int32,string,bool> person3, [3] class '<>f__AnonymousType0`3'<string,int32,string> person4, [4] class '<>f__AnonymousType2`4'<string,int32,bool,string> person5) IL_0000: nop IL_0001: ldstr "CS" IL_0006: ldc.i4.s 20 IL_0008: ldc.i4.1 IL_0009: newobj instance void class '<>f__AnonymousType0`3'<string,int32,bool>::.ctor(!0, !1, !2) IL_000e: stloc.0 IL_000f: ldstr "CS" IL_0014: ldc.i4.s 23 IL_0016: ldc.i4.0 IL_0017: newobj instance void class '<>f__AnonymousType0`3'<string,int32,bool>::.ctor(!0, !1, !2) IL_001c: stloc.1 IL_001d: ldc.i4.s 20 IL_001f: ldstr "CS" IL_0024: ldc.i4.1 IL_0025: newobj instance void class '<>f__AnonymousType1`3'<int32,string,bool>::.ctor(!0, !1, !2) IL_002a: stloc.2 IL_002b: ldstr "CS" IL_0030: ldc.i4.s 20 IL_0032: ldstr bytearray (37 75 ) // 7u IL_0037: newobj instance void class '<>f__AnonymousType0`3'<string,int32,string>::.ctor(!0, !1, !2) IL_003c: stloc.3 IL_003d: ldstr "CS" IL_0042: ldc.i4.s 20 IL_0044: ldc.i4.1 IL_0045: ldstr "HN" IL_004a: newobj instance void class '<>f__AnonymousType2`4'<string,int32,bool,string>::.ctor(!0, !1, !2, !3) IL_004f: stloc.s person5 IL_0051: ldloc.0 IL_0052: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() IL_0057: ldloc.1 IL_0058: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() IL_005d: call bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type, class [mscorlib]System.Type) IL_0062: call void [mscorlib]System.Console::WriteLine(bool) IL_0067: nop IL_0068: ldloc.0 IL_0069: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() IL_006e: ldloc.2 IL_006f: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() IL_0074: call bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type, class [mscorlib]System.Type) IL_0079: call void [mscorlib]System.Console::WriteLine(bool) IL_007e: nop IL_007f: ldloc.0 IL_0080: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() IL_0085: ldloc.3 IL_0086: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() IL_008b: call bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type, class [mscorlib]System.Type) IL_0090: call void [mscorlib]System.Console::WriteLine(bool) IL_0095: nop IL_0096: ldloc.0 IL_0097: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() IL_009c: ldloc.s person5 IL_009e: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType() IL_00a3: call bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type, class [mscorlib]System.Type) IL_00a8: call void [mscorlib]System.Console::WriteLine(bool) IL_00ad: nop IL_00ae: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() IL_00b3: pop IL_00b4: ret } // end of method Program::Main
上面的代码中,我们声明了5个匿名类的对象,我们先看person1和person2两个对象,这两个对象包含的字段名称一样,只是值不一样,那么对象person1和person2就是同一个泛型类(<>f__AnonymousType0`3)的对象,并且我们他们的泛型参数类型都是string,int32,bool,所以最后的Console.WriteLine(person1.GetType() == person2.GetType());的结果是True。person1和person2是同一个泛型类的对象,并且泛型参数类型一样。
person1和person3两个对象虽然都具有Name、Age、Gender这3个字段名称,但是由于字段名称不一样(其实我就是将字段的先后顺序改变了一下,这个地方说的字段名称不一样指的是person1中的第一个参数名称为Name,person3中的第一个参数名称为Age,两个字段名称不一样),导致person1和person3属于了两个不同的泛型类的对象,从IL代码中我们可以看出,person1是泛型类<>f__AnonymousType0`3的一个对象,并且泛型参数类型是string,int32,bool;而person3是泛型类<>f__AnonymousType1`3的一个对象,泛型参数类型为int32,string,bool,所以最后的Console.WriteLine(person1.GetType() == person2.GetType());的结果是False。person1和person不是同一个泛型类的对象,并且泛型参数类型不一样。
person1和person4两个对象具有3个相同的字段名称,从IL代码来看person1和person4是同一个泛型类<>f__AnonymousType0`3的对象,但是为什么最后Console.WriteLine(person1.GetType() == person4.GetType());的值为False呢?原因是,虽然person1和person4属于同一个泛型类的对象,但是对象的泛型参数类型却是不同的,person1的泛型参数类型为string,int32,bool;而person4的泛型参数类型为string,int32,string;所以最后的输出结果为False。person1和person4是同一个泛型类的对象,但是泛型参数类型不一样。
person1和person5两个对象,我们根据前边的知识,不用看IL代码就应该知道他们肯定不是同一个泛型类的对象,因为它们的字段个数都不一样,person1是泛型类<>f__AnonymousType0`3的一个对象,泛型参数类型为string,int32,bool;而person5是泛型类<>f__AnonymousType2`4的一个对象,泛型参数类型为string,int32,bool,string;语句Console.WriteLine(person1.GetType() == person5.GetType());的执行结果为False。person1和person5不是同一个泛型类的对象,并且泛型参数类型不一样。