C#特性-对象集合初始化器介绍

C# 3.0为你提供了对象集合初始化器:

/// <summary>
/// 图书类
/// </summary>
public class Book
{
  /// <summary>
  /// 图书名称
  /// </summary>
  public string Title { get; set; }
  /// <summary>
  /// 单价
  /// </summary>
  public float Price { get; set; }
  /// <summary>
  /// 作者
  /// </summary>
  public string Author { get; set; }
  /// <summary>
  /// ISBN号
  /// </summary>
  public string ISBN { get; set; }
}
//对象初始化器
Book book = new Book { Title="Inside COM",ISBN="123-456-789"};

现在你想初始化几个就初始化几个,不需要出现这种情况:

public Book():this("")
{
}
public Book(string title):this(title,0)
{
}
public Book(string title, float price):this(title,price,"")
{
}
public Book(string title, float price, string isbn)
{
    this.Title = title;
    this.Price = price;
    this.ISBN = isbn;
}

这一串的构造方法都是为了应付不同的初始化情况。
好了,来看看对象初始化器编译器在后面为我们做了些什么呢?
使用Reflector反编译程序集:

代码如下:

Book <>g__initLocal0 = new Book();
<>g__initLocal0.Title = "Inside COM";
<>g__initLocal0.ISBN = "123-456-789";
Book book = <>g__initLocal0;

C#编译器生成了一个新的局部变量<>g__initLocal0,调用Book的默认无参构造方法初始化它,然后对它的属性进行赋值,最后将这个局部变量赋值给book。看到这里,我们应该想到,要使用对象初始化器,那么这个对象必须有一个无参构造方法,如果你给这个方法写了一个有参构造方法而将它的默认无参构造方法覆盖了并且没有提供一个新的无参构造方法,那么使用对象初始化器编译的时候是不会通过的(不过想不通,为啥C#编译器生成这么一个奇怪的局部变量名字,还有为啥不直接使用book呢)。像下面的代码不更好:

代码如下:

Book book = new Book();
book.Title = "Inside COM";
book.ISBN = "123-456-789";

后来我发现我是在debug模式下编译的,换到release模式下变成了这样:

代码如下:

Book <>g__initLocal0 = new Book();
<>g__initLocal0.Title = "Inside COM";
<>g__initLocal0.ISBN = "123-456-789";

被优化了。上面介绍的就是对象初始化器了,那什么是集合初始化器呢?

代码如下:

IList<Book> books = new List<Book>();
//这里就使用了对象初始化器,学以致用吧
books.Add(new Book { Title = "Inside COM", ISBN = "123-456-789",Price=20 });
books.Add(new Book { Title = "Inside C#", ISBN = "123-356-d89",Price=100 });
books.Add(new Book { Title = "Linq", ISBN = "123-d56-d89", Price = 120 });

这样的代码没少写吧,实际上也许比这更复杂,有了C# 3.0我们睡觉都想笑:

代码如下:

IList<Book> books = new List<Book> {
     new Book { Title = "Inside COM", ISBN = "123-456-789",Price=20 },
     new Book { Title = "Inside C#", ISBN = "123-356-d89",Price=100 },
     new Book { Title = "Linq", ISBN = "123-d56-d89", Price = 120 }
};

还是像刚才一样,我们来欣赏一下C#编译器为我们生成的代码:

代码如下:

List<Book> <>g__initLocal0 = new List<Book>();
    Book <>g__initLocal1 = new Book();
    <>g__initLocal1.Title = "Inside COM";
    <>g__initLocal1.ISBN = "123-456-789";
    <>g__initLocal1.Price = 20f;
    <>g__initLocal0.Add(<>g__initLocal1);
    Book <>g__initLocal2 = new Book();
    <>g__initLocal2.Title = "Inside C#";
    <>g__initLocal2.ISBN = "123-356-d89";
    <>g__initLocal2.Price = 100f;
    <>g__initLocal0.Add(<>g__initLocal2);
    Book <>g__initLocal3 = new Book();
    <>g__initLocal3.Title = "Linq";
    <>g__initLocal3.ISBN = "123-d56-d89";
    <>g__initLocal3.Price = 120f;
    <>g__initLocal0.Add(<>g__initLocal3);

从上面的代码来看,编译器自动的调用了List的无参构造方法,然后实例化一个个的Book,再一个个的Add进去,和我们原来的做法没有什么不同,但是,这是编译器为我们做的,所以简省了我们很多的编码工作。
对象集合初始化器就算介绍完了。有人也许会说,不就是个syntx sugar么,有什么。是的,确实是个语法糖。在编译器发展早期,编译器科学家门一直在想方设法的优化编译器生成的代码,这个时候,编译器做的主要是对机器优化,因为那个时候机器的时间非常宝贵,机器运算速度也不快,今天我们有了足够好的机器了(但并不是说我们可以不关注性能的编写程序),而且作为编写软件的人来说,比机器的时间宝贵得多,所以今天的编译器也在向人优化了,从编程语言的发展之路来讲,今天的编程语言比昨天的语言更高级,也更人性化了,我们只要编写更少的代码,更符合人的思维的代码,而只要关注我们值的关注的地方。体力活儿就交给编译器吧。

附加:

刚开始想想这对象集合初始化器也许就一鸡肋,没啥用,不就减少一点点代码么,像这种简单的初始化工作,大部分代码生成器都可以来干。后来在研究匿名类型的时候突然发现,如果没有这个对象初始化器,匿名类型是不是要复杂一些?或者就是难以实现?
var test = new{Key="test",Value="test"};如果没有对象初始化器,匿名类型该怎么办?

(0)

相关推荐

  • 详解C#中使用对象或集合的初始值设定项初始化的操作

    使用对象初始值设定项初始化对象 可以使用对象初始值设定项以声明方式初始化类型对象,而无需显式调用类型的构造函数. 下面的示例演示如何将对象初始值设定项用于命名对象.编译器通过先访问默认实例构造函数然后处理成员初始化处理对象初始值设定项.因此,如果默认构造函数在类中声明为 private,那么需要公共访问权的对象初始值设定项将失败. 下面的示例演示如何使用对象初始值设定项初始化新的 StudentName 类型. public class Program { public static void

  • c#构造初始化的顺序浅析

    这个很基础的知识,但我至今才意识到它.想想也很失败. 直接上代码:很简单 复制代码 代码如下: public class Base    {        int i=0; public Base()        {            System.Console.WriteLine("我是基类构造器");        } } class Program    {        static void Main(string[] args)        {          

  • C#中数组初始化、反转和排序用法实例

    本文实例讲述了C#中数组初始化.反转和排序用法.分享给大家供大家参考.具体如下: 下面的代码演示了在C#中定义和初始化数组,然后对其进行赋值,排序和反转的操作方法: using System; public class ArraySample { public static void Main() { // Create and initialize a new array instance. Array strArr = Array.CreateInstance(typeof(string),

  • c#对象初始化顺序实例分析

    本文实例分析了c#对象初始化顺序.分享给大家供大家参考.具体如下: using System; using System.Collections.Generic; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { A a = new B(); Console.ReadLine(); } } class A { //调用到这个构造函数时:x=1,y

  • C#数组初始化简析

    题外话:学习.NET已经有一年了,从C#->ASP.NET->WPF.主要以看电子书为主,比较少写代码.现在回头学习以前接触过的,随着知识与经验的的积累. 总是有各种惊喜,震惊!C#数组就是其中之一,我把它作为自己博客园的处女作. C#数组与其它C系列语言有着很多的不同,以前接触的时候理解出现很大的偏差.尤其是对多维数组的认识.多维数组与C语言相比是一个新概念.而最开始的 时候我把它当成交错数组的特殊类型. 首先重二维数组与简单的交错数组的初始化与访问开始 复制代码 代码如下: int[,]

  • C#中结构(struct)的部分初始化和完全初始化实例分析

    本文实例分析了C#中结构(struct)的部分初始化和完全初始化,分享给大家供大家参考.具体分析如下: 假设有这样一个值类型struct,如下所示: public struct Size { public int Length; public int Width; public int Area() { return Length*Width; } } 一.客户端,给所有struct字段初始化后调用方法 class Program { static void Main(string[] args

  • C#类的创建与初始化实例解析

    本文以一个实例简单实现了类的创建与初始化,实现代码如下所示: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace C_program_test { class Person { public string Name; //因为Name没有赋值,而它是string类型的,所以它的默认值就是Null public int Age; //因为Age和Gender也

  • C#中数组初始化与数组元素复制的方法

    本文实例讲述了C#中数组初始化与数组元素复制的方法.分享给大家供大家参考.具体如下: 下面的代码演示如何创建和初始化数组,以及C#中如何将数组元素从一个复制到另外一个的方法. using System; public class ArraySample { public static void Main() { // 创建和初始化数组 int[] intArr = new int[5] {1,2,3,4,5}; Object[] objArr = new Object[5] {10,20,30,

  • C#特性-对象集合初始化器介绍

    C# 3.0为你提供了对象集合初始化器: /// <summary> /// 图书类 /// </summary> public class Book { /// <summary> /// 图书名称 /// </summary> public string Title { get; set; } /// <summary> /// 单价 /// </summary> public float Price { get; set; }

  • C#自定义集合初始化器

    对int类型集合初始化,这样写: static void Main(string[] args) { var list = new List<int> {0, 1}; foreach (var item in list) { Console.WriteLine(item); } Console.ReadKey(); } 对键值对集合初始化,这样写: static void Main(string[] args) { var dic = new Dictionary<string, str

  • Swift初始化器与可选链的使用方法介绍

    目录 初始化器 required 属性观察器 可失败初始化器 反初始化器(deinit) 可选链(Optional Chaining) 初始化器 required 用required修饰指定初始化器,表明其所有子类都必须实现该初始化器(通过继承或者重写实现) 如果子类重写了required初始化器,也必须加上required,不用加上override class Person { required init() {} init(age: Int) {} } class Student: Pers

  • c# 9.0新特性——模块初始化器

    作者:MarkKang 出处:https://www.cnblogs.com/markkang/ 1 背景动机 关于模块或者程序集初始化工作一直是C#的一个痛点,微软内部外部都有大量的报告反应很多客户一直被这个问题困扰,这还不算没有统计上的客户.那么解决这个问题,还有基于什么样的考虑呢? 在库加载的时候,能以最小的开销.无需用户显式调用任何接口,使客户做一些期望的和一次性的初始化. 当前静态构造函数方法的一个最大的问题是运行时会对带有静态构造函数的类型做一些额外的检查.这是因为要决定静态构造函数

  • ECMAscript新特性对象介绍

    目录 1.对象的属性 1.1属性表示法 2.计算属性名 3.Object 的方法 3.1Object.is() 方法 3.2Object.assign()方法 4.super 关键字 5.对象的扩展运算符 1.对象的属性 1.1属性表示法 ECMAScript 2015允许在大括号里面,直接写入变量和函数,作为对象的属性和方法.这样的书写更加简洁. 示例代码如下所示: let name = '一碗周' let job = '前端攻城狮' // 属性表示法 直接写入变量 let obj1 = {

  • Java中List集合的深入介绍(超级推荐!)

    目录 1,Java集合介绍 2,List介绍 2.1 ArrayList集合 2.2 LinkedList集合 3,List常用方法 3.1 ArrayList 基本操作 3.2 LinkedList 基本操作 4,ArrayList和LinkedList比较 5,ArrayList源码分析 6,LinkedList源码分析 7,小结 1,Java集合介绍 作为一个程序猿,Java集合类可以说是我们在工作中运用最多.最频繁的类.相比于数组(Array)来说,集合类的长度可变,更加方便开发. Ja

  • Python3.7 新特性之dataclass装饰器

    Python 3.7中一个令人兴奋的新特性是 data classes . 数据类通常是一个主要包含数据的类,尽管实际上没有任何限制. 它是使用新的 @dataclass 装饰器创建的,如下所示: from dataclasses import dataclass @dataclass class DataClassCard: rank: str suit: str 此代码以及本教程中的所有其他示例仅适用于 Python 3.7 及更高版本. 注意: 当然在 Python 3.6 版本也可以使用

  • C++11新特性之列表初始化的具体使用

    目录 统一的初始化方法 列表初始化的一些使用细节 初始化列表 1.任何长度的初始化列表 2.std::initialzer-list的使用细节 列表初始化防止类型收窄 在我们实际编程中,我们经常会碰到变量初始化的问题,对于不同的变量初始化的手段多种多样,比如说对于一个数组我们可以使用 int arr[] = {1,2,3}的方式初始化,又比如对于一个简单的结构体: struct A { int x; int y; }a={1,2}; 这些不同的初始化方法都有各自的适用范围和作用,且对于类来说不能

  • java spring mvc处理器映射器介绍

    目录 一.RequestMappingHandlerMapping解析映射简单介绍 二.@RequestMapping解析源码流程 三.@RequestMapping映射源码流程 四.@RequestMapping解析源码 五.@RequestMapping映射源码 前言: 本文源码基于spring-framework-5.3.10. mvc是spring源码中的一个子模块! 一.RequestMappingHandlerMapping解析映射简单介绍 @RequestMapping通过Requ

  • Effective C# 使用成员初始化器而不是赋值语句

    一般情况下,一个类都会有多个构造函数.随着时间的推移,成员变量.构造函数不断增加.为了处理这种情况最方便的办法就是:在声明变量的时候进行初始化,而不是在每个构造函数中进行.无论是类成员(静态变量)合适实例变量,我们都应该充分利用初始化器的语法. C#编程在,一般在声明一个变量的同时我们会对其进行初始化: 复制代码 代码如下: 1 class Employee 2 { 3 private List<Employee> empList = new List<Employee>(); 4

随机推荐