简化C#的不可变对象图

在C#中创建一个简单的不可变类很容易,开发者只需要创建一个构造函数且不创建公共setter。但这往往还不够。最终开发者或许会想要创建深层图,考虑到效率原因,应该通过建造者(builder)创建它。或者也许开发者想要创建一些方法,返回包含已变更字段的该对象的复本(如DateTime的AddMinutes方法),以此来实现非破坏性更新。构建全部这些建造者和方法非常冗长乏味,因此也容易出错。

\

Andrew L Arnott提出了一个解决方案,它依靠基于T4的代码生成器。T4代表“文本模版转换工具包”,Text Template Transformation Toolkit。它处于Visual Studio代码生成功能的核心位置,诸如实体框架等库都依赖它。Andrew的T4脚本接收一个可变类并创建一个不可变的版本。

\

该工具包做出了一个略有争议的决定,即不生成公共构造器。相反,他期望开发者使用静态的Create方法,或是从Default实例开始然后修改它。这通过使用WithXxx方法实现,每个属性都有一个对应的方法。

\
\

不过,我们可以做更多的改进。对拥有许多属性的类,如果我们需要一次改变若干属性,那么在每个属性变更时都分配一个新对象作为中间步骤,将是一种浪费并且会增加GC的压力。因此我们还添加了一个With方法,为每个出现在类中的属性接收可选参数,从而支持属性的批量变更。最后,对于需要对对象进行多处变更,却又希望通过多个步骤实现(或者只是倾向于使用属性setter而不是调用With-方法)的场景,我们可以创建一个Builder类,它在构建过程中使用可变的类 ,并且将在完成后返回一个不可变复本。这一模式与.Net Framework中的String和StringBuilder非常类似,也与之前提到过的最新不可变集合相似。

\
\

当然,如果开发者不喜欢这些决定,也可以很容易地修改T4模版。Andrew故意将模版分解成更小的文件,从而让修改变得更容易。开发者还可以添加自己的扩展而无需对基础模版进行重大改变。

\

与所有良好编写的代码生成器相似,这里也大量使用了分部方法。分部方法允许开发者向代码生成器生成的方法中添加额外的逻辑,而不必修改生成的文件。例如,开发者可以实现一个类来为不可变对象设定部分默认值。未实现的分部方法将被编译器自动剥离出来,因此不会导致运行时开销。

\

开发者如果希望进一步了解Arron的实验,可以在他的博客中阅读关于不可变对象图的文章。

\

查看英文原文Making Immutable Object Graphs Easier in C#

\

感谢姚琪琳对本文的审校。

\

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值