2025 AI基础设施风向标,不看必后悔!#AI基础设施峰会 了解详情
写点什么

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

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

关注

评论

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

redis精讲系列介绍七-过期策略

Nick

Redis 核心技术与实战 6月月更 redis精讲 redis 过期策略 redis 底层原理

JUnit VS TestNG

FunTester

爆肝!阿里大佬自曝10w字Java面试核心知识手册,基础到高级足足涵盖30个技术专题

Java全栈架构师

Java spring 架构 面试 JVM

SRE Lesson One -- 写给SRE新手的入门手册

耳东@Erdong

SRE SRE Lesson One

JVM调优简要思想及简单案例-老年代空间分配担保机制

zarmnosaj

6月月更

axios框架入门教程

倔强的牛角

axios 6月月更

微服务测试效率治理

阿泽🧸

微服务 6月月更

数据治理的重要性

奔向架构师

数据治理 数据资产 6月月更

leetcode 279. Perfect Squares 完全平方数(中等)

okokabcd

LeetCode 动态规划 算法与数据结构

Go Web 编程入门:验证器

宇宙之一粟

Go 语言 表单校验 6月月更

uni-app进阶之样式框架/生产环境【day10】

恒山其若陋兮

6月月更

linux几个没用但是有趣的命令

入门小站

Linux

盘点常见的漏洞利用方式

穿过生命散发芬芳

漏洞利用 6月月更

Android 修改系统屏幕亮度及监听

yechaoa

android 6月月更 Brightness

唐太宗把微服务的“心跳机制”玩到了极致!

悟空聊架构

微服务 Eureka 悟空聊架构 6月月更 心跳机制

如何使用物联网低代码平台进行报表管理?

AIRIOT

物联网 低代码平台

vue2升级vue3:this.$createElement is not a function—动态组件升级

zhoulujun

在线文本按行批量反转工具

入门小站

工具

JAVA SOCKET编程——TCP/UDP

乌龟哥哥

6月月更

微博关闭发布多个兼职诈骗信息违规账号:如何打击数据造假灰产

石头IT视角

Java Core 「14」J.U.C 线程池-Future & FutureTask

Samson

学习笔记 Java core 6月月更

数据库每日一题---第19天:排名靠前的旅行者

知心宝贝

数据库 前端 后端 云 原生云 CTO 6月月更

DOM 节点

Jason199

DOM js DOM事件 6月月更

vue2升级vue3:webpack vue-loader 打包配置

zhoulujun

vite webpack vue-loader

【愚公系列】2022年06月 通用职责分配原则(九)-受保护变量原则

愚公搬代码

6月月更

再次认识 WebAssembly

devpoint

typescript webassembly 6月月更

滴滴工程效能平台建设之路

laofo

互联网 DevOps 研发效能 持续交付 工程效能

有一说一,高并发系统设计其实一点都不难!

Java全栈架构师

Java 程序员 面试 高并发 架构设计

eureka的解析

卢卡多多

Eureka 6月月更

在线JSON转HTMLTable工具

入门小站

工具

SRE Lesson One -- Day2 熟练使用 Markdown

耳东@Erdong

SRE 6月月更 SRE Lesson One

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