当前位置: 首页 > news >正文

.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 需要实现的方法
▲ 实现一个 ICollection 需要实现的方法

最简单的集合初始化器

只是做一个集合初始化器的话并不需要写上面那么多的代码。

实际上,你只需要两个步骤:

  1. 实现 IEnumerable 接口或任何子接口
  2. 有一个 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/"
};

这是一个可以发挥创造力的语法糖

利用单个和多个参数的集合初始化器,以及带索引的集合初始化器,我们甚至可以用集合初始化器去构造一些看起来不像集合的类型。这又是一波语法糖!

当然有一点值得注意,使用集合初始化器初始化的时候,Addthis[] 的初始化是不能同时使用的。

参考资料

事实上微软的官方文档中并没有对集合初始化器的最简实现有多少描述,所以以下的参考实际上并没有用。

  • 英文:Object and Collection Initializers (C# Programming Guide) - Microsoft Docs
  • 中文:对象和集合初始值设定项(C# 编程指南) - Microsoft Docs

相关文章:

  • .NET 中让 Task 支持带超时的异步等待
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • WPF 的 ElementName 在 ContextMenu 中无法绑定成功?试试使用 x:Reference!
  • WPF 中的 NameScope
  • Windows 下的高 DPI 应用开发(UWP / WPF / Windows Forms / Win32)
  • 技术、产品、交流、思考 - 微软技术暨生态大会 2018
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)
  • WindowsXamlHost:在 WPF 中使用 UWP 控件库中的控件
  • WindowsXamlHost:在 WPF 中使用 UWP 的控件(Windows Community Toolkit)
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)
  • 编写 Target 检测 MSBuild / dotnet build 此次编译是否是差量编译
  • 使用 Win2D 绘制带图片纹理的圆(或椭圆)
  • Win2D 中的游戏循环:CanvasAnimatedControl
  • 使用 Windows 10 中的加速度计(Accelerometer,重力传感器)
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • AWS实战 - 利用IAM对S3做访问控制
  • ES6 ...操作符
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • JS笔记四:作用域、变量(函数)提升
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • Js基础知识(四) - js运行原理与机制
  • js正则,这点儿就够用了
  • TypeScript迭代器
  • Vue学习第二天
  • vue学习系列(二)vue-cli
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 看域名解析域名安全对SEO的影响
  • 前端
  • 数组的操作
  • 微信小程序填坑清单
  • 从如何停掉 Promise 链说起
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • (a /b)*c的值
  • (SpringBoot)第七章:SpringBoot日志文件
  • (二)斐波那契Fabonacci函数
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (数据结构)顺序表的定义
  • (转)可以带来幸福的一本书
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • **登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**
  • ../depcomp: line 571: exec: g++: not found
  • .libPaths()设置包加载目录
  • @RequestBody详解:用于获取请求体中的Json格式参数
  • @RequestBody与@ResponseBody的使用
  • []AT 指令 收发短信和GPRS上网 SIM508/548
  • [【JSON2WEB】 13 基于REST2SQL 和 Amis 的 SQL 查询分析器
  • [20170728]oracle保留字.txt
  • [bzoj 3534][Sdoi2014] 重建
  • [BZOJ] 2006: [NOI2010]超级钢琴
  • [BZOJ1010] [HNOI2008] 玩具装箱toy (斜率优化)