.NET 中创建支持集合初始化器的类型
对象初始化器和集合初始化器只是语法糖,但是能让你的代码看起来更加清晰。至少能让对象初始化的代码和其他业务执行的代码分开,可读性会好一些。
本文将编写一个类型,可以使用集合初始化器构造这个类型。不只是添加元素的集合初始化器,还有带索引的集合初始化器。
稍微提一下对象初始化器
很普通的类型就可以支持对象初始化器,只需要对象有可以 set 的属性或者可访问的字段即可。
public class Walterlv
{
public string Site { get; set; }
}
初始化时可以使用
var walterlv = new Walterlv
{
Site = "https://walterlv.com",
};
基本上大家编写的类或多或少都会支持对象初始化器,所以本文不会对此谈论更多的内容。
通常的集合初始化器
当你定义一个集合的时候,你会发现你的类型已经天然支持集合初始化器了。比如你定义了下面这个集合:
public class WalterlvCollection : ICollection<Walterlv>
{
// 省略集合定义的代码。
}
那么此集合初始化的代码就可以写成下面这样:
var collection = new WalterlvCollection
{
new Walterlv(),
new Walterlv(),
}
实际上你会发现实现一个 ICollection 是一件非常繁琐的事情。

▲ 实现一个 ICollection 需要实现的方法
最简单的集合初始化器
只是做一个集合初始化器的话并不需要写上面那么多的代码。
实际上,你只需要两个步骤:
- 实现 IEnumerable 接口或任何子接口
- 有一个 Add 方法
就像这样:
public class WalterlvCollection : IEnumerable
{
private readonly List<Walterlv> _list = new List<Walterlv>();
public IEnumerator GetEnumerator()=>_list.GetEnumerator();
public void Add(string site) => _list.Add(new Walterlv { Site = site });
}
于是你就可以像一个一般的集合那样去使用集合初始化器了:
var collection = new WalterlvCollection
{
"https://walterlv.com/",
"https://blog.csdn.net/wpwalter",
};
多个参数的集合初始化器
刚刚我们的例子中 Add 方法只有一个参数,实际上也可以是多个参数。
public class WalterlvCollection : IEnumerable
{
private readonly List<Walterlv> _list = new List<Walterlv>();
public IEnumerator GetEnumerator()=>_list.GetEnumerator();
public void Add(string site, bool includeProtocol) => _list.Add(new Walterlv { Site = site });
}
现在初始化的方法就有点像字典了:
var collection = new WalterlvCollection
{
{ "https://walterlv.com/", true },
{ "https://blog.csdn.net/wpwalter", true },
};
当然你也可以写更多参数,看起来更加丧心病狂。
public class WalterlvCollection : IEnumerable
{
private readonly List<Walterlv> _list = new List<Walterlv>();
public IEnumerator GetEnumerator()=>_list.GetEnumerator();
public void Add(string site, bool includeProtocol, string author)
=> _list.Add(new Walterlv { Site = site });
}
var collection = new WalterlvCollection
{
{ "https://walterlv.com/", true, "walterlv" },
{ "https://blog.csdn.net/wpwalter", true, "walterlv" },
};
带索引集合初始化器
如果你期望的初始化方法是索引,实际上也不需要 Add 方法。只需要增加一个索引的定义即可:
public class WalterlvCollection : IEnumerable
{
private readonly List<Walterlv> _list = new List<Walterlv>();
public IEnumerator GetEnumerator()=>_list.GetEnumerator();
public string this[string site]
{
get => _list.Find(x => x.Site == site).Site;
// 请忽略这里的 Bug,这只是一个语法糖的示例。
set => _list.Add(new Walterlv { Site = value });
}
}
这时,可以使用索引方式的集合初始化器:
var collection = new WalterlvCollection
{
["吕毅"] = "https://walterlv.com/",
["林德熙"] = "https://lindexi.gitee.io/"
};
这是一个可以发挥创造力的语法糖
利用单个和多个参数的集合初始化器,以及带索引的集合初始化器,我们甚至可以用集合初始化器去构造一些看起来不像集合的类型。这又是一波语法糖!
当然有一点值得注意,使用集合初始化器初始化的时候,Add 和 this[] 的初始化是不能同时使用的。
参考资料
事实上微软的官方文档中并没有对集合初始化器的最简实现有多少描述,所以以下的参考实际上并没有用。
- 英文:Object and Collection Initializers (C# Programming Guide) - Microsoft Docs
- 中文:对象和集合初始值设定项(C# 编程指南) - Microsoft Docs
.NET 中创建支持集合初始化器的类型的更多相关文章
- C#中的自动属性、隐式类型var、对象初始化器与集合初始化器、扩展方法
1.自动属性(Auto-Implemented Properties) //以前的写法 .net2.0 private string _userName; public string UserName ...
- C#语法糖之第二篇: 参数默认值和命名参数 对象初始化器与集合初始化器
今天继续写上一篇文章C#4.0语法糖之第二篇,在开始今天的文章之前感谢各位园友的支持,通过昨天写的文章,今天有很多园友们也提出了文章中的一些不足,再次感谢这些关心我的园友,在以后些文章的过程中不断的完 ...
- C#高级知识点概要(3) - 特性、自动属性、对象集合初始化器、扩展方法、Lambda表达式和Linq查询
1.特性(Attributes) 特性(Attributes),MSDN的定义是:公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法 ...
- C# 3.0 / C# 3.5 对象集合初始化器、匿名类
对象集合初始化器 在 .NET 2.0 中构造一个对象的方法一是提供一个重载的构造函数,二是用默认的构造函数生成一个对象,然后对其属性进行赋值. 在 .NET 3.5/C# 3.0 中,我们有一种更好 ...
- Linq专题之集合初始化器
集合初始化器用来初始化一个集合,和对象初始化器有点类似,都是用一对{}来初始化. using System; using System.Collections.Generic; using Syste ...
- C# 对象初始化器和集合初始化器
/// <summary>/// 图书类/// </summary>public class Book { /// <summary> /// 图书 ...
- [C#6] 7-索引初始化器
0. 目录 C#6 新增特性目录 1. 老版本的代码 private static void Main() { var dictionary = new Dictionary<int, stri ...
- .NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器
开篇:在日常的.NET开发学习中,我们往往会接触到一些较新的语法,它们相对以前的老语法相比,做了很多的改进,简化了很多繁杂的代码格式,也大大减少了我们这些菜鸟码农的代码量.但是,在开心欢乐之余,我们也 ...
- dotNet中初始化器的使用
dotNet中初始化器的使用 2013年12月7日 13:27 有两类初始化器: 对象初始化器和集合初始化器 比如现在有一个User类: Public class User { public in ...
随机推荐
- 【cocos2d-x 3.5】Lua动画API
1.加载动画 local node = cc.CSLoader:createNode("ActionTimeline/DemoPlayer_skeleton.csb") local ...
- nodejs+express工程 在npm install之后或使用npm install bootstrap命令安装bootstrap之后
nodejs+express工程 在npm install之后或使用npm install bootstrap命令安装bootstrap之后引入bootstrap文件 如果你的静态资源存放在多个目录下 ...
- PHImageManager 获取图片模糊
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; options.synchronous = true; o ...
- Android5.0免Root截屏,录屏
http://blog.csdn.net/wds1181977/article/details/52174840 MediaProjection介绍 MediaProjection可以用来捕捉屏幕,具 ...
- Python3.x:定时获取页面数据存入数据库
Python3.x:定时获取页面数据存入数据库 #间隔五分钟采集一次数据入库 import pymysql import urllib.request from bs4 import Beautifu ...
- Sublime Text3编辑器简介
Sublime Text3编辑器简介 下载地址 绿色中文版v3.3038下载地址:http://www.cncrk.com/downinfo/60832.html 官方网址(英文安装版)下载地址:ht ...
- 树莓派实践部分——P2P文件下载机torrent之Raspberry Pi管理
树莓派实践--P2P文件下载机torrent之Raspberry Pi管理 一.树莓派配置文件共享软件deluge 在进行实践之前,先通过命令sudo apt-get update 和sudo apt ...
- 20145221 《Java程序设计》第八周学习总结
20145221 <Java程序设计>第八周学习总结 教材学习内容总结 第十五章部分 - 通用API 通用API 日志: 日志对信息安全意义重大,审计.取证.入侵检测等都会用到日志信息 日 ...
- IMX6Q GPIO定义
ret = gpio_request_array(mx6q_sabresd_flexcan_gpios, ARRAY_SIZE(mx6q_sabresd_ ...
- Linux环境下如何配置IP地址、MAC地址
Linux环境下如何配置IP地址.MAC地址 1.配置IP地址 进入配置IP地址路径,进行修改即可 cd /etc/network vim interface 加入以下内容: iface eth0 i ...