纯函数能否引用属性?C#场景下纯函数判定与实现优化探讨
第一个Sum实例方法的纯函数判定
首先明确纯函数的两个核心判定标准:相同输入始终返回相同输出、无任何副作用。
你给出的第一个Sum()实例方法不属于纯函数,理由如下:
- 它的返回值依赖实例的可读写属性
X、Y,即便两次调用的显式入参(无)完全相同,只要调用间隙修改了同一实例的X/Y值,返回结果就会发生变化,不符合“相同输入返回相同输出”的要求。 - 你提到的“把X、Y算作函数参数”的主张不成立:函数参数是调用方在调用时刻显式传递的输入,而X、Y是绑定到实例生命周期的状态,调用方调用
Sum()时不需要也无法显式传入这两个值,甚至可能不知道Sum()依赖这两个属性,完全不符合参数的定义。
补充:如果把
X、Y修改为不可变属性(比如用get; init;定义,实例构造完成后无法修改),那么此时Sum()可以被认定为纯函数,因为实例构造完成后Sum的返回值就完全固定,不会再发生变化。
扩展方法重构的合理性判断
这种重构没有改变核心逻辑,也没有让Sum变成纯函数:
扩展方法本质是静态方法的语法糖,你给出的Sum扩展方法虽然把Summer实例作为显式入参,但只要入参s的X/Y属性可以修改,那么同一个s两次调用Sum的返回值依然可能变化,和原来的实例方法没有本质区别,谈不上更合理。
重构的技术层面优势分析
你提到的几个技术维度都没有明显优势:
- 运行速度:扩展方法编译后就是普通静态方法,和实例方法的调用开销几乎一致,没有性能差异。
- 内存效率:两种实现的执行逻辑完全一致,没有额外的对象分配或内存占用,内存效率完全相同。
- 测试便捷性:两种实现的测试逻辑完全一致,都需要构造
Summer实例、给X/Y赋值、调用Sum断言结果,没有简化测试步骤。 - 逻辑易推理:如果是你自己可控的
Summer类,把Sum作为实例方法反而更符合内聚性原则,使用者可以直接在Summer类的定义里看到Sum方法,不需要额外找扩展类,反而更容易理解逻辑。只有当你需要为无法修改的第三方Summer类新增方法,或者要避免原类过于臃肿时,扩展方法才有设计层面的优势,不属于技术层面的增益。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

