C#中_onScroll += _ => _onScroll3?.Invoke()这类委托订阅作用是什么
问题解答
核心代码作用解释
你提到的两行代码本质都是事件转发的实现:
_onScroll += _ => _onScroll3?.Invoke();:_onScroll是带int参数的事件类型,Lambda表达式里的_是显式丢弃不需要用到的传入int参数。意思是每次_onScroll事件被触发时,就自动触发一次_onScroll3事件。_onScroll2 += () => _onScroll3?.Invoke();:_onScroll2是无参事件类型,Lambda不需要接收参数,作用和上面一致:_onScroll2触发时自动转发触发_onScroll3。
调用Invoke的原因
有两个核心原因:
- 空安全触发要求:C#的事件本质是多播委托,如果没有任何订阅者,事件变量的值就是
null,直接调用_onScroll3()会抛出空引用异常。?.Invoke()是C# 6及以上版本提供的空条件调用语法,会先判断_onScroll3是否不为空,只有存在订阅者时才会执行触发逻辑,避免空引用报错,且该判断是原子操作,线程安全。 - 事件触发的规范写法:事件只能在声明它的类内部直接触发,
Invoke就是委托/事件的标准触发方法,执行时会按顺序调用所有订阅了_onScroll3的回调方法。
你观察到的“订阅者同步”现象说明
这不是订阅者真的同步了,是转发逻辑带来的效果:你只给_onScroll、_onScroll2各加了一个转发到_onScroll3的回调,所以不管后续给_onScroll3新增/移除多少订阅者,_onScroll、_onScroll2触发时都会执行当时_onScroll3的所有订阅回调,看起来就像是两个事件的订阅者和_onScroll3同步了。
这种写法的常用场景是把多个不同签名的同源事件(比如不同场景下的滚动事件)统一转发到同一个入口事件,业务代码只需要订阅一次入口事件就可以接收所有相关通知,减少重复订阅的冗余代码。
额外注意点
你示例中的DoWork、DoWork2方法每次调用都会给事件新增一次匿名Lambda订阅,而匿名方法没有办法直接移除订阅,多次调用会导致_onScroll3被重复触发多次,实际使用时要避免这种重复订阅的问题。
内容的提问来源于stack exchange,提问作者Dani Grosu
相关产品推荐
相关产品推荐

