引用与回调(提供者/工厂):两类成员变量初始化方式差异解析
类A与类B的成员变量初始化差异及引用、回调的区别
我们直接结合你给出的C#代码,拆解两类初始化方式的核心差异,以及你提到的“引用传递”和“回调”的本质区别:
一、类A的初始化逻辑(ref参数传递)
类A的SetA方法使用ref关键字接收参数,调用时直接传递bCollection的变量引用:
a.SetA(ref bCollection);
- 赋值时机:调用
SetA的瞬间,就把当前bCollection指向的对象引用,直接赋值给_collectionA。这个过程是立即完成的。 - 引用绑定特性:一旦赋值完成,
_collectionA就和bCollection彻底解绑——哪怕后续bCollection被重新赋值为新的BlockingCollection<int>对象,_collectionA依然持有最初那个对象的引用。 - 注:这里的
ref在当前代码里其实有点多余(方法内部没有修改传入的collectionA变量本身),本质和直接传递引用类型参数的效果一致,但核心是直接传递“当前对象的引用”。
二、类B的初始化逻辑(回调委托传递)
类B的SetB方法接收一个Func<BlockingCollection<int>>类型的委托(也就是你说的“回调”),调用时传入的是一个Lambda表达式:
b.SetB(() => bCollection);
- 赋值时机:调用
SetB时,并没有直接获取bCollection的引用,只是把() => bCollection这个“获取引用的逻辑”保存下来。只有当执行collectionBProvider()时,才会去读取当前bCollection指向的对象引用,再赋值给_collectionB。 - 引用绑定特性:如果
collectionBProvider()是延迟执行的(比如把委托保存下来,在后续某个时间点再调用),那么它会拿到bCollection当前最新的引用。比如如果在调用SetB后,你修改了bCollection指向新对象,那么后续执行回调时,_collectionB会绑定到新对象上。 - 灵活性:回调的本质是传递“行为”而非“值”——你可以在Lambda里写任意逻辑,比如每次调用都创建新对象:
() => new BlockingCollection<int>(30),或者根据条件返回不同对象,这是直接传递引用做不到的。
三、核心差异总结
| 维度 | 类A(ref参数) | 类B(回调委托) |
|---|---|---|
| 传递内容 | 当前对象的直接引用 | 获取对象的逻辑/行为 |
| 赋值时机 | 调用方法时立即完成 | 执行回调时才完成(可延迟) |
| 后续引用更新影响 | 不受原变量后续赋值影响 | 若延迟执行,会跟随原变量的最新引用 |
| 灵活性 | 固定一次性赋值,无扩展空间 | 可自定义获取逻辑,支持动态场景 |
四、引用与回调的本质区别
- 引用传递:传递的是对象的“地址值”,是一种值的传递(引用类型的传递本质是传引用的值),目标对象直接绑定当前的引用,逻辑简单直接。
- 回调:传递的是一段可执行的代码逻辑,是行为的传递,可以在需要的时候再执行逻辑获取值,支持动态、延迟、自定义的场景,灵活性更强。
内容的提问来源于stack exchange,提问作者Vesa95
相关产品推荐
相关产品推荐

