写点什么

简化 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:272038
用户头像

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

关注

评论

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

啃透Alibaba这份面试通关宝典,信心倍增!我成功拿下今年第15个Offer

Geek_0c76c3

Java 数据库 开源 程序员 架构

在 Go 语言中使用 exec 包执行 Shell 命令

宇宙之一粟

Shell Go 语言 10月月更

超详细教程:在Blender中打造毛毡风格角色

Renderbus瑞云渲染农场

blender Renderbus瑞云渲染

太强了!阿里巴巴最新开源303页Spring全家桶高级笔记,深入瓦解源码

Geek_0c76c3

Java 开源 程序员 架构 开发

从零手写react-router

helloworld1024fd

JavaScript

阿里全新推出:微服务突击手册,把所有操作都写出来了|超清PDF

程序知音

Java 微服务 阿里 SpringCloud 后端技术

怎样徒手写一个React

helloworld1024fd

JavaScript

JPEX推出竞猜世界杯冠军球队活动,质押平台通证赢奖金

股市老人

一文带你理解@RefreshScope注解实现动态刷新原理

JAVA旭阳

Java spring 10月月更

idea启动build过慢

拾光师

IDEA 10月月更

一文带你玩转ProtoBuf

王中阳Go

Go 微服务 RPC protobuf 10月月更

React源码分析7-state计算流程和优先级

goClient1992

React

打造面向工业4.0的智能工厂01|云边协同架构助力视觉AI缺陷检测应用构建

EMQ映云科技

AI 物联网 IoT emqx 10月月更

鹅厂二面,nginx回忆录

有态度的马甲

leetcode 220. Contains Duplicate III 存在重复元素 III(困难)

okokabcd

LeetCode 数据结构与算法

TDengine 3.0 中如何编译、创建和使用自定义函数

TDengine

数据库 tdengine 开源 时序数据库

腾讯强推Spring Security速成笔记太香了!认证授权一键搞定

程序知音

Java 架构 spring security 后端技术 Spirng

云安全将进入黄金时代 - Gartner 报告解读

HummerCloud

云计算 云安全 Gartner

EasyRecovery2023绿色版下载安装教程分享

茶色酒

EasyRecovery15 easyrecovery2023

基础设施 NFTScan 正式发布 Avalanche 网络 NFT 浏览器

NFT Research

区块链 NFT web3 数据基础设施 Avalanche

自己手写一个redux

helloworld1024fd

JavaScript

京东的“618”高并发秒杀终极版教程!(Java语言设计)

程序知音

Java 架构 并发编程 高并发 后端技术

实践了上万次,原来这些才是敏捷测试需要遵循的原则

敏捷开发

敏捷 测试 单元测试

《数字经济全景白皮书》证券财富管理篇 重磅发布

易观分析

金融 证券

会声会影2023全新功能介绍

茶色酒

会声会影 会声会影2023

CleanMyMac X2023苹果电脑必备下载软件

茶色酒

CleanMyMac X

面试官:你说说Vue中的组件和插件有什么区别?

CoderBin

vue.js 面试 前端 组件 10月月更

太神了!阿里p7大佬总结的Java面试心得,起始—进阶—突击,一应俱全!

Geek_0c76c3

Java 数据库 开源 程序员 架构

技术内幕 | StarRocks Pipeline 执行框架(上)

StarRocks

数据库

easyrecovery15注册机非常强大的数据恢复软件

茶色酒

EasyRecovery Easyrecovery破解 EasyRecovery15

一步步实现React-Hooks核心原理

helloworld1024fd

JavaScript

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