写点什么

简化 C#的不可变对象图

  • 2013-05-15
  • 本文字数:1070 字

    阅读完需:约 4 分钟

在 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 )关注我们,并与我们的编辑和其他读者朋友交流。

2013-05-15 09:271726
用户头像

发布了 256 篇内容, 共 72.2 次阅读, 收获喜欢 10 次。

关注

评论

发布
暂无评论
发现更多内容

只需10分钟,让你的企业应用具备OCR能力

明道云

Hi,Contributor,有一份专属周边礼包等你领取!

SphereEx

开源社区 ShardingSphere SphereEx Contributor 周边

建设区块链基础设施,加速区块链等新技术与传统行业深度融合发展

CECBC

WebRTC DTLS | 谈谈 DTLS Fragment

泰一

DTLS

复杂JSON结构创建语法

FunTester

Java json 接口测试 测试开发 FunTester

Android C++系列:Linux文件系统(一)

轻口味

c++ android jni 11月日更

直播 | 大数据能力体系构建的技术方法全在这了!

百度开发者中心

大数据 百度 直播 开发者沙龙

数字藏品是什么?有风险吗?谁来监管?

CECBC

提升RTC音频体验 - 从搞懂硬件开始

Wilber

音视频 RTC 3A 音频技术 音频3A

【Flutter 专题】04 图解第一个程序遇到的安装依赖问题

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 11月日更

Java将增加虚拟线程,挑战Go协程

编程宝库

Java golang 并发

研发效能提升的八项实践建议

博文视点Broadview

北京主题展|2022第十五届北京国际物联网展览会

InfoQ_caf7dbb9aa8a

在浏览器里使用 SAP GUI

汪子熙

SAP abap SAPGUI 11月日更

论文解读丨文本行识别模型的再思考

华为云开发者联盟

数据集 文档 文本 文本识别 语言模型

货币“大动作”,中国数字货币DCEP即将落地!

CECBC

SAP UI 搜索分页技术

汪子熙

JavaScript Web SAP 11月日更

明道云初学者如何速成报表管理系统

明道云

Supersonic Superstars挑战赛,FeoFun、Black Candy斩获大奖

flutter 开发中 vscode 插件推荐 3

坚果

flutter 11月日更

部署Apollo

小鲍侃java

11月日更

Vue进阶(贰佰):前端UI框架介绍

No Silver Bullet

Vue UI 11月日更

2021 年中国敏捷行业现状调查全面启动

爱吃小舅的鱼

敏捷开发 敏捷转型 问卷调研

dart系列之:创建Library package

程序那些事

flutter dart 程序那些事 11月日更

Java编程中忽略这些细节,Bug肯定找上你

华为云开发者联盟

Java 编程 对象 垃圾回收 switch语句

从原理带你掌握Spring MVC拦截处理器知识

华为云开发者联盟

Spring MVC 拦截器 拦截处理器 HTTP请求

前端开发:Node版本引起的报错问题

三掌柜

11月日更

【LeetCode】整数替换Java题解

Albert

算法 LeetCode 11月日更

精选案例 | YRCloudFile 引领自动驾驶存储技术新趋势

焱融科技

自动驾驶 云计算 分布式 高性能 文件存储

【高并发】ScheduledThreadPoolExecutor与Timer的区别和简单示例

冰河

Java 并发编程 多线程 高并发 异步编程

北京智博会主题展|2022第十五届北京国际物联网展览会

InfoQ_caf7dbb9aa8a

简化C#的不可变对象图_后端_Jonathan Allen_InfoQ精选文章