前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.NET 中创建支持集合初始化器的类型

.NET 中创建支持集合初始化器的类型

作者头像
walterlv
发布2020-02-10 16:18:15
5400
发布2020-02-10 16:18:15
举报
文章被收录于专栏:walterlv - 吕毅的博客

对象初始化器和集合初始化器只是语法糖,但是能让你的代码看起来更加清晰。至少能让对象初始化的代码和其他业务执行的代码分开,可读性会好一些。

本文将编写一个类型,可以使用集合初始化器构造这个类型。不只是添加元素的集合初始化器,还有带索引的集合初始化器。


稍微提一下对象初始化器

很普通的类型就可以支持对象初始化器,只需要对象有可以 set 的属性或者可访问的字段即可。

代码语言:javascript
复制
public class Walterlv
{
    public string Site { get; set; }
}

初始化时可以使用

代码语言:javascript
复制
var walterlv = new Walterlv
{
    Site = "https://blog.walterlv.com",
};

基本上大家编写的类或多或少都会支持对象初始化器,所以本文不会对此谈论更多的内容。

通常的集合初始化器

当你定义一个集合的时候,你会发现你的类型已经天然支持集合初始化器了。比如你定义了下面这个集合:

代码语言:javascript
复制
public class WalterlvCollection : ICollection<Walterlv>
{
    // 省略集合定义的代码。
}

那么此集合初始化的代码就可以写成下面这样:

代码语言:javascript
复制
var collection = new WalterlvCollection
{
    new Walterlv(),
    new Walterlv(),
}

实际上你会发现实现一个 ICollection 是一件非常繁琐的事情。

实现一个 ICollection 需要实现的方法
实现一个 ICollection 需要实现的方法

▲ 实现一个 ICollection 需要实现的方法

最简单的集合初始化器

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

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

  1. 实现 IEnumerable 接口或任何子接口
  2. 有一个 Add 方法

就像这样:

代码语言:javascript
复制
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 });
}

于是你就可以像一个一般的集合那样去使用集合初始化器了:

代码语言:javascript
复制
var collection = new WalterlvCollection
{
    "https://blog.walterlv.com/",
    "https://walterlv.blog.csdn.net/",
};

多个参数的集合初始化器

刚刚我们的例子中 Add 方法只有一个参数,实际上也可以是多个参数。

代码语言:javascript
复制
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 });
}

现在初始化的方法就有点像字典了:

代码语言:javascript
复制
var collection = new WalterlvCollection
{
    { "https://blog.walterlv.com/", true },
    { "https://walterlv.blog.csdn.net/", true },
};

当然你也可以写更多参数,看起来更加丧心病狂。

代码语言:javascript
复制
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 });
}
代码语言:javascript
复制
var collection = new WalterlvCollection
{
    { "https://blog.walterlv.com/", true, "walterlv" },
    { "https://walterlv.blog.csdn.net/", true, "walterlv" },
};

带索引集合初始化器

如果你期望的初始化方法是索引,实际上也不需要 Add 方法。只需要增加一个索引的定义即可:

代码语言:javascript
复制
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 });
    }
}

这时,可以使用索引方式的集合初始化器:

代码语言:javascript
复制
var collection = new WalterlvCollection
{
    ["吕毅"] = "https://blog.walterlv.com/",
    ["林德熙"] = "https://blog.lindexi.com/"
};

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

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

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

参考资料

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

本文会经常更新,请阅读原文: https://blog.walterlv.com/post/create-class-that-supports-collection-initializer.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 (walter.lv@qq.com)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-10-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 稍微提一下对象初始化器
  • 通常的集合初始化器
  • 最简单的集合初始化器
  • 多个参数的集合初始化器
  • 带索引集合初始化器
  • 这是一个可以发挥创造力的语法糖
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档