BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

C#的未来:不可变类

| 作者 Jonathan Allen 关注 593 他的粉丝 ,译者 邵思华 关注 3 他的粉丝 发布于 2015年6月8日. 估计阅读时间: 6 分钟 | QCon上海2018 关注大数据平台技术选型、搭建、系统迁移和优化的经验。

本文是C#的未来系列文章的最后一篇了,这次我们将讨论第159号提案,它建议在编译器中加入对不可变类的支持。虽说在C#中创建不可变类型一直以来都是可以做到的,并且C# 6还将进一步简化这一过程,但目前还没有一种方式能够“将类声明为不可变”,并让编译器对这一声明进行校验。

这一提议看起来似乎并非十分重要,因为对类进行手动检查也不是非常困难的事。但如果缺少了对于不可变性的某种声明,就难以了解开发者的意图。应用程序的开发者可能会做出某些假设,例如可以在多线程环境中安全地使用某个类,却发现在下一个版本中,类库的开发者为其加入了某个属性的setter方法,或是其它任何一种可变的、非线程安全的特性。

第159号提议推荐通过使用一个“immutable”关键字或者属性,显式地表明某个类型在任何情况下都不能更改。此外,一个不可变对象只能够引用其它不可变对象。

不可变对象的构造函数也具有一些限制,尤其是它们不能够通过“this”变量调用方法,因为这有可能将该对象在构造过程完成之前“泄漏”出去,从而破坏了对不可变性的承诺。至于这种泄漏应当引起一个错误还是一次警告,这一点可以再议。Sam Harwell写道:

我比较倾向于发出警告的做法,虽然这种做法并不常见,并且也不是推荐的编码方式,但也很难肯定地说绝对没有人需要编写这样的代码。

不可变性与Pure

第一眼看上去,不可变性与Pure(纯对象或方法)约束的作用似乎是相同的,但它们之间确实存在着一些重要的不同之处。

  • 一个纯对象可以引用其它并未标注为Pure的对象,而正如之前所说,不可变类型不允许引用可变类型。
  • 纯方法不允许进行任何可见的状态更改,包括对当前对象与任何参数的更改。
  • 纯方法或纯属性可以更改内部状态。举例来说,它可以将某个计算的结果进行缓存以便重用。这一点并不违反纯方法的承诺,因为外部的观察者不会察觉到内部的变化。而不可变对象则没有这种能力。
  • 不可变对象中的方法只保证不会更改对象的状态,但允许对输入参数的状态进行更改。

考虑到这些不同之处的存在,相信你会看到许多同时具有不可变性与Pure特性的对象。

泛型与不可变性

泛型类型也将支持不可变性。要实现这一点,通常需要为每个类型参数都设定一个不可变性的限制。但这一条规则还有待商榷,有人认为可以直接从类型的参数中推断出不可变性,而无需显式地将其列为不可变。

欺骗

在某些情况下,你必须对类型系统进行欺骗,这一点已经得到了认可。打个比方,ImmutableArray是对一个普通数组的封装。而如果按照这条提议的基本原则来说,这种行为是不允许出现的。为了处理这种场景,你可以在这个类的标注中进行声明,表示你是有意地违背了这条原则,并且已经仔细地考虑过这样做的后果。这种做法与“unsafe”关键字的行为很相似,因为后者也是为了这种场合才出现的。

由于“unsafe”关键字的意思已经固定了,因此该提议考虑使用其它的关键字。目前来说,得到最多认可的关键字是“mutable”,不过看起来大家对此都不是十分满意。

只读性 —— 隐式或显式

在一个不可变对象中,每个字段在语义上都是只读的。某些开发者认为不必显式地进行声明,这可以减少代码的冗长度。另一些人则认为,正如在静态类中声明静态字段一样,每个字段都应该显式地标注为只读。

内部或外部校验

具体在何处强制不可变性,这一点需要认真考虑。某些人认为,正如代码契约与Pure属性一样,不可变性也应当由某个外部分析器进行处理。这样一来,开发团队就能够自行决定是否需要以编程方式强制不可变性。

另一部分开发者则认为,正因为如此,不可变性更不应当由外部工具进行处理。他们希望编译器能够进行不可变性的检查,这样就不会在无意中破坏了它的不可变性。

来自于微软的Jared Parsons写道:

我认为在这种场合使用分析器是错误的方案,在一个单一的C#项目中,要强制一系列规则的应用,甚至是对某种C#的变体进行分析,分析器都是一种优秀的选择。因为我对编译过程具有掌控权,因此可以随意地选择并使用分析器。

而如果需要在多个项目中强制某些规则,尤其是在这些项目属于不同开发者的情况下,分析器的作用就降低了。没有什么机制能够强制对某个项目引用通过某种分析器进行扫描,这种情况下唯一有效的强制措施就是双方的携手合作了。

这种情况与Pure属性的承诺不同,后者只是表示在某个对象中的任何方法或是属性都不会“产生任何可见的状态更改”。

查看英文原文:C# Futures: Immutable Classes


感谢张龙对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入InfoQ读者交流群InfoQ好读者)。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT