C# 匿名类型

原文链接:https://www.cnblogs.com/edisonchou/p/4088959.html

匿名类型就是匿名类

一、匿名类:[ C# 3.0/.NET 3.x 新增特性 ]

匿名类声明一

var annoyCla1 = new {ID=1 };
Console.WriteLine(annoyCla1);
//输出结果:{ ID = 1 }

 

IL 代码

 

 

 IL 编译器将匿名类型 生成为一个普通的类'<>f__AnonymousType0'。

 第二种写法:

string[] fruits = { "apple", "banana", "mango", "orange",
                      "passionfruit", "grape" };

var query =
    fruits.Select((fruit, index) =>
                      new { index, str = fruit.Substring(0, index) });

foreach (var obj in query)
{
    Console.WriteLine("{0}", obj);
}

/*
 This code produces the following output:

 {index=0, str=}
 {index=1, str=b}
 {index=2, str=ma}
 {index=3, str=ora}
 {index=4, str=pass}
 {index=5, str=grape}
*/

 

 

 

二、匿名类型的赋值

其实匿名类型是通过构造函数赋值。匿名类型在编译器编译后,会生成只读属性和构造函数,然后在构造函数中给字段赋值(只读属性是不能通过对象初始值设定项赋值的)。匿名类型的赋值只是在写法上看起来像对象初始值设定项罢了。

 var annoyCla1 = new
    {
        ID = 10010,
        Name = "EdisonChou",
        Age = 25
    };
Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla1.ID,annoyCla1.Name, annoyCla1.Age);
 

IL代码

 

 

 从上图可以看出:  

 (1)匿名类被编译后会生成一个[泛型类]

(2)匿名类所生成的属性都是只读的,可以看出与其对应的字段也是只读的;

  

  所以,如果我们在程序中为属性赋值,那么会出现错误;

  

  (3)可以看出,匿名类还继承了基类的三个方法:Equals,GetHashCode和ToString;我们可以看看它为我们所生成的ToString方法是怎么来实现的:

 

1.3 匿名类的共享

  可以想象一下,如果我们的代码中定义了很多匿名类,那么是不是编译器会为每一个匿名类都生成一个泛型类呢?答案是否定的,编译器考虑得很远,避免了重复地生成类型。换句话说,定义了多个匿名类的话如果符合一定条件则可以共享一个泛型类。下面,我们就来看看有哪几种情况:

  (1)如果定义的匿名类与之前定义过的一模一样:属性类型和顺序都一致,那么默认共享前一个泛型类

复制代码
            var annoyCla1 = new
            {
                ID = 10010,
                Name = "EdisonChou",
                Age = 25
            };

            Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla1.ID,
                annoyCla1.Name, annoyCla1.Age);
            Console.WriteLine(annoyCla1.ToString());

            // 02.属性类型和顺序与annoyCla1一致,那么共同使用一个匿名类
            var annoyCla2 = new
                {
                    ID = 10086,
                    Name = "WncudChou",
                    Age = 25
                };
            Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla1.ID,
                annoyCla1.Name, annoyCla1.Age);
            Console.WriteLine("Is The Same Class of 1 and 2:{0}",
                annoyCla1.GetType() == annoyCla2.GetType());    
复制代码

  通过上述代码中的最后两行:我们可以判断其是否是一个类型?答案是:True

  (2)如果属性名称和顺序一致,但属性类型不同,那么还是共同使用一个泛型类,只是泛型参数改变了而已,所以在运行时会生成不同的类:

复制代码
            var annoyCla3 = new
                {
                    ID = "EdisonChou",
                    Name = 10010,
                    Age = 25
                };
            Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla3.ID,
                annoyCla3.Name, annoyCla3.Age);
            Console.WriteLine("Is The Same Class of 2 and 3:{0}",
                annoyCla3.GetType() == annoyCla2.GetType());
复制代码

  我们刚刚说到虽然共享了同一个泛型类,只是泛型参数改变了而已,所以在运行时会生成不同的类。所以,那么可以猜测到最后两行代码所显示的结果应该是False,他们虽然都使用了一个泛型类,但是在运行时生成了两个不同的类。

  (3)如果数据型名称和类型相同,但顺序不同,那么编译器会重新创建一个匿名类

复制代码
            var annoyCla4 = new
                {
                    Name = "EdisonChou",
                    ID = 10010,
                    Age = 25
                };
            Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla4.ID,
                annoyCla4.Name, annoyCla4.Age);
            Console.WriteLine("Is The Same Class of 2 and 4:{0}",
                annoyCla4.GetType() == annoyCla2.GetType());
复制代码

  运行判断结果为:False

  通过Reflector,可以发现,编译器确实重新生成了一个泛型类:

 

 

 

匿名类型的一些规则:

 

1)如果两个匿名类型的结构完全一样,那么它们之间可以进行赋值操作

2)匿名类型是引用类型,编译器会生成相应的class,而不是struct

3)匿名类型也是Object类派生的,但是无法将Object类型转型回匿名类型。

4)匿名类型不能作为一个方法的参数和返回值。

上述3)4)的原因在于,匿名类型的名称是有编译器按一定规则生成的,在写代码的时候并不知道我们定义的匿名类型的具体名称。

因此,无法从Object转型回匿名类型,也不能指定方法的参数类型和返回值类型。

1、匿名类型的使用场景

    当类中只定义了一些字段和属性,没有构造函数、方法、委托事件等比较复杂的成员,而且这个类的使用频率不高时,我们就可以使用匿名类型。linq中用于保存数据

2、匿名类型的定义

    定义一个匿名类型时,需要使用var关键字和对象初始化语法。

    var:编译器会在编译时自动生成新类的定义。

    初始化:编译器会为类创建私有的字段和(只读)属性。

        var student = new { Name = "Wyhon", Age = 18 };
        Console.WriteLine($"Name = {student.Name}, Age = {student.Age}");

    可以看到,在new后面没有类型名称,这是编译器确定我们使用匿名类型的方式。

3、匿名类型的内部表现方式

    匿名类型默认直接继承于Object,而且重写了Object的ToString()、GetHashCode()、Equals()方法。

            static void Main(string[] args)
            {
                var student = new { Name = "Wyhon", Age = 18 };
                ReflectOverAnonymousType(student);
            }
            public static void ReflectOverAnonymousType(Object obj)
            {
                Console.WriteLine($"实例类型: {obj.GetType().Name}");
                Console.WriteLine($"父类:{obj.GetType().BaseType}");
                Console.WriteLine($"ToString():{obj.ToString()}");
                Console.WriteLine($"GetHashCode():{obj.GetHashCode()}");
            }

                 

可以看到,匿名类型的名称是由编译器决定的。

4、匿名类型间的比较

            public static void EqualTest()
            {
                var student1 = new { Name = "Wyhon", age = 20 };
                var student2 = new { Name = "Wyhon", age = 20 };
     
     
                if (student1.Equals(student2))
                {
                    Console.WriteLine("student1 Equals to student2");
                }
                else
                {
                    Console.WriteLine("student1 do not Equals to student2");
                }
     
     
                if(student1 == student2)
                {
                    Console.WriteLine("student1 == student2");
                }
                else
                {
                    Console.WriteLine("student1 != student2");
                }
     
     
                if(student1.GetType().Name == student2.GetType().Name)
                {
                    Console.WriteLine("student1.GetType().Name == student2.GetType().Name");
                }
                else
                {
                    Console.WriteLine("student1.GetType().Name != student2.GetType().Name");
                }
                Console.WriteLine();
                ReflectOverAnonymousType(student1);
                ReflectOverAnonymousType(student2);
            }

运行结果:

                

可以看出:Equals:比较的是匿名类型中属性(字段)的内容。

                 ==:比较的是匿名类型的引用。

                 最后就是,当两个或多个匿名类型都指定了属性序列,名称相同并且顺序一致,编译器会将它们视为相同类型的实例,共享相同的类型信息。

posted @ 2021-09-11 14:26  小林野夫  阅读(2338)  评论(0编辑  收藏  举报
原文链接:https://www.cnblogs.com/cdaniu/