C#匿名类型(Anonymous Type)学习日记

当我们不要定义复杂的方法,事件,构造函数这样复杂的类的时候,可以动态的生成一个自定义的数据类型 --> 匿名类型。

1.定义匿名类型

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

var : 编译器会在编译时自动生成新类定义(我们无法在C#代码中看到类的名称)。

初始化:它将告诉编译器为新创建的类型创建私有的后台字段和(只读的)属性。

通过传递参数构建一个匿名类型,并打印相关信息

private static void BiuldAnonymousType(string make, string color, int currSp)
{
    // 使用传入参数构建匿名类型
    var car = new { Make = make, Color = color, CurrSp = currSp };

    // 获取属性数据
    Console.WriteLine($"{car.Color} 的 {car.Make} 时速{car.CurrSp}");

    // 匿名类型包含对System.Object中每个虚方法(virtual)的自定义实现
    Console.WriteLine($"ToString={car.ToString()}");
}

调用:也可以使用硬编码构建匿名类型

public static void Show()
{
    Console.WriteLine("fun with anonymous types");

    // 注意 匿名类型也可以使用硬编码创建
    // 构建一个匿名对象表示汽车
    var car = new { Make = "honda", Color = "blue", CurrSp = 180 };

    // 输出颜色和车
    Console.WriteLine($"我的车是{car.Color}{car.Make}");

    // 调用辅助方法通过参数创建匿名类型
    BiuldAnonymousType("baoma", "white", 220);
}

2.匿名类型的内部表示方式

所有的匿名类型都自动继承Object,所以我们可以在 car 对象上ToString,GetHashCode,Equals,我们尝试调用一下:

private static void ReflectOverAnonymousType(object obj)
{
    Console.WriteLine($"对象实例:{obj.GetType().Name}");
    Console.WriteLine($"类型: {obj.GetType().Name} 基类: {obj.GetType().BaseType}");
    Console.WriteLine($"toString():{obj.ToString()}");
    Console.WriteLine($"getHashCode():{obj.GetHashCode()}");
}

调用以及结果:

public static void Show()
{
    Console.WriteLine("fun with anonymous types");

    // 构建一个匿名对象表示汽车
    var car = new { Make = "honda", Color = "blue", CurrSp = 180 };

    ReflectOverAnonymousType(car);
}

car对象的类型是:<>f__AnonymousType0`3(你的或许不同),匿名类型名称由编译器觉得,我们无从干涉,CIL代码。

3.方法 ToString() 和 GetHashCode() 的实现

1.ToString()

public override string ToString()
{
    StringBuilder builder = new StringBuilder();
    builder.Append("{ Color = ");
    builder.Append(this.<Color>i_Field);
    builder.Append(", Make = ");
    builder.Append(this.<Make>i_Field);
    builder.Append(", CurrSp = ");
    builder.Append(this.<CurrSp>i_Field);
    builder.Append("}");
    return builder.ToString();
}

2.GetHashCode()

它使用每个匿名类型的变量计算出散列值作为System.Collections.Generic.EqualityComparer<T>的类型输入,仅当两个匿名类型有相同的属性并且被赋予了相同的值,才会产生相同的散列值。

4.匿名类型的相等语义

Equals()

private static void EqualityTest()
{
    // 构建两个匿名类型,拥有相同的名称/值对
    var oneCar = new { Make = "honda", Color = "blue", CurrSp = 180 };
    var twoCar = new { Make = "honda", Color = "blue", CurrSp = 180 };

    // 调用Equals
    if (oneCar.Equals(twoCar))
    {
        Console.WriteLine("Equals“同一个匿名对象");
    }
    else
    {
        Console.WriteLine("Equals“不是 同一个匿名对象");
    }

    // 使用 == 操作符
    if (oneCar == twoCar)
    {
        Console.WriteLine("==“同一个匿名对象");
    }
    else
    {
        Console.WriteLine("==“不是 同一个匿名对象");
    }

    // 比较对象类型
    if (oneCar.GetType().Name == twoCar.GetType().Name)
    {
        Console.WriteLine("同一个类型");
    }
    else
    {
        Console.WriteLine("不同类型");
    }

    ReflectOverAnonymousType(oneCar);
    ReflectOverAnonymousType(twoCar);
}

分析一下这样的结果:

1.Equals():编译器重写Equals()在判断对象相等时使用了基于值得语义(如:笔记两个对象的每一个数据成员的值)

2.==操作符:是因为匿名类型没有重载 相等操作符(==,!=),所以==比较的是引用,而不是内容。

3.GetType():是因为如果我们同一程序集中声明两个相同的(属性相同)匿名类型,编译器只会生成一个匿名类型的定义。

5.包含匿名类型的匿名类型

var order = new
{
    car = new { Make = "honda", Color = "blue", CurrSp = 180 },
    price = 200000
};

ReflectOverAnonymousType(order);

总结:

其实,我们应该谨慎使用匿名类型,尤其在使用LINQ时,永远不要因为匿名类型的出现而放弃使用强类型的类或结构。

其实,匿名类型本身有许多限制:

  • 你并没有控制匿名类型的名称
  • 匿名类型继承System.Object
  • 匿名类型的字段和属性总是只读的
  • 匿名类型不支持事件,自定义方法,自定义操作符和自定义重写
  • 匿名类型是隐式封闭的(implicit sealed)
  • 匿名类型的实体创建只使用默认构造函数

如果,我们需要快速定义一个实体的形状,而不需要定义其功能时,可以使用匿名类型。

学无止境,望各位看官多多指教。

时间: 2024-08-29 12:10:44

C#匿名类型(Anonymous Type)学习日记的相关文章

C#匿名类型 - Anonymous Types

[C#匿名类型 - Anonymous Types] Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. The type name is generated by the compiler and is not available at

如何把匿名类型.GetType()返回的对象传进泛型里面[转]

//怎么取得匿名类型的Type放到 //泛型T当中?? var 匿名 = new { A = 0, B = 1 }; Type t = 匿名.GetType(); //然后下面 var xx = dbContext.Database.SqlQuery<t>("sql"); //就悲剧了 var xx2 = dbContext.Database.SqlQuery<dynamic>("sql"); //xx2有列表,但是都是Object..~~~

学习日记-----各种问题

用.net做B/S结构的系统,您是用几层结构来开发,每一层之间的关系以及为什么要这样分层? 答: 从下至上分别为:数据访问层.业务逻辑层(又或成为领域层).表示层 数据访问层:有时候也称为是持久层,其功能主要是负责数据库的访问 业务逻辑层:是整个系统的核心,它与这个系统的业务(领域)有关 表示层:是系统的UI部分,负责使用者与整个系统的交互.  优点:  分工明确,条理清晰,易于调试,而且具有可扩展性. 缺点:  增加成本. 分层式结构究竟其优势何在? 1.开发人员可以只关注整个结构中的其中某一

java学习日记第一天

java 学习日记 第一天 java学习准备工作 首先环境配置:一个是jdk安装,另一个编译工具 eclipse ,安装下载教程网上很多 找了一个照着做就行 : 上述步骤完成,我们就可以打开eclipse进行我们第一个程序的编写啦当然是编写我们熟悉的helloWorld创建一个Java Perfect 目前好像基本都习惯用工程管理我们就建一个java工程然后点开工程在src右键new一个class,不用问这是啥这是啥,先把程序跑起来,慢慢就懂了我们在{}写我们的程序,这就好比helloworld

informatica 学习日记整理

1. INFORMATICA CLIENT的使用 1.1 Repository Manager 的使用 1.1.1 创建Repository. 前提: a. 在ODBC数据源管理器中新建一个数据源连接至你要创建Repository的数据库(例:jzjxdev) b. 要在你要连接的数据库中新建一个用户(例:name: ETL password: ETL) 现在你可以创建一个Repository了.选择Repository – Create Repository,输入Repository Name

理解隐式类型、对象初始化程序和匿名类型

在C# 3.0中,几乎每个新特性都是为LINQ服务的.所以,本文将介绍下面几个在C# 3.0中引入的新特性: 自动实现的属性 隐式类型的局部变量 对象和集合初始化程序 隐式类型的数组 匿名类型 其实这几个特性都是比较容易理解的,对于这几个特性,编译器帮我们做了更多的事情(想想匿名方法和迭代器块),从而简化我们的代码. 自动实现的属性 在C# 3.0以前,当我们定义属性的时候,一般使用下面的代码 public class Book { private int _id; private string

15.C#回顾及匿名类型(八章8.1-8.5)

今天的篇幅应该会很长,除了回顾前面学的一些,还有写一些关于匿名类型的相关知识,总体上对后续的学习很有帮助,学好了,后面更容易理解,不明白的,那就前面多翻几次,看多了总是会理解的.那么,进入正题吧. 自动实现属性 我们的很多工作都是由编译器帮我们去完成,如我们要说的自动实现属性.使用自动实现属性时,C#3执行了一个简单的编译转换,在类的内部生成一个私有的字段,使用不友好的命名(防止命名冲突).在C#2中允许为取值和赋值方法指定不同的访问权限,现在我们还可以创建静态的自动属性. 隐式类型 使用隐式类

学习日记之解释器模式和Effective C++

解释器模式(interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. (1),如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言的句子.这样可以构建一个解释器,该解释器通过解释这些句子来解决该问题. (2),当一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象的语法树时,可使用解释器模式. (3),容易改变和扩展文法,因为该模式使用类来表示文法规则,你可以使用继承来改变和扩展该文法

学习日记之中介者模式和Effective C++

中介者模式(Mediator):用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变他们之间的交互. (1),中介者模式很容易在系统中应用,也很容易在系统中误用.当系统出现多对多交互复杂的对象群时,不要急于使用中介者模式,而要反思你在系统的设计上是不是合理. (2),中介者的出现减少了各个对象的耦合,使得可以独立地改变和复用各个对象和中介者. (3),由于把对象如何协作进行了抽象,将中介者作为一个独立的概念并将其封装在一个对象中,这样关注