跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
C Sharp 弱事件模式
”︁
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
{{DISPLAYTITLE:C#弱事件模式}} '''C#弱事件模式'''是一种特殊的事件处理机制,用于解决标准事件订阅可能导致的内存泄漏问题。本指南将详细介绍其原理、实现方式及实际应用场景。 == 概述 == 在标准事件模型中,事件发布者持有对订阅者的强引用,可能导致订阅者无法被垃圾回收(即使不再需要)。弱事件模式通过使用'''弱引用'''(<code>WeakReference</code>)来打破这种强依赖关系。 === 核心问题 === 传统事件订阅的潜在问题: <syntaxhighlight lang="csharp"> public class Publisher { public event EventHandler? EventRaised; } public class Subscriber { public Subscriber(Publisher pub) { pub.EventRaised += HandleEvent; // 强引用! } private void HandleEvent(object? sender, EventArgs e) { } } </syntaxhighlight> 若<code>Publisher</code>比<code>Subscriber</code>生命周期更长,即使<code>Subscriber</code>不再使用,仍会因事件绑定而保留在内存中。 == 实现方式 == .NET 提供两种主要实现方案: === 1. WeakEventManager 类 === 位于<code>System.Windows</code>命名空间(WPF基础库): <syntaxhighlight lang="csharp"> public class CustomWeakEventManager : WeakEventManager { public static void AddHandler(Publisher source, EventHandler handler) { CurrentManager.ProtectedAddHandler(source, handler); } protected override void StartListening(object source) => ((Publisher)source).EventRaised += DeliverEvent; protected override void StopListening(object source) => ((Publisher)source).EventRaised -= DeliverEvent; } </syntaxhighlight> === 2. 手动弱引用实现 === 基础实现示例: <syntaxhighlight lang="csharp"> public class WeakEvent<TEventArgs> { private readonly List<WeakReference<EventHandler<TEventArgs>>> _handlers = new(); public void AddHandler(EventHandler<TEventArgs> handler) { _handlers.Add(new WeakReference<EventHandler<TEventArgs>>(handler)); } public void Raise(object sender, TEventArgs e) { foreach (var weakRef in _handlers.ToArray()) { if (weakRef.TryGetTarget(out var handler)) handler(sender, e); else _handlers.Remove(weakRef); // 清理无效引用 } } } </syntaxhighlight> == 生命周期对比 == <mermaid> sequenceDiagram participant Publisher participant Subscriber participant GC as Garbage Collector Note over Publisher,Subscriber: 标准事件模式 Subscriber->>Publisher: 订阅事件(强引用) GC->>Subscriber: 无法回收(被Publisher引用) Note over Publisher,Subscriber: 弱事件模式 Subscriber->>Publisher: 订阅事件(弱引用) GC->>Subscriber: 可正常回收 </mermaid> == 实际案例 == '''场景:''' 日志系统需要向多个临时分析器广播消息,但不应阻止分析器被回收。 <syntaxhighlight lang="csharp"> public class LogSystem { private readonly WeakEvent<LogEventArgs> _logEvent = new(); public void AddListener(EventHandler<LogEventArgs> handler) => _logEvent.AddHandler(handler); public void Log(string message) { _logEvent.Raise(this, new LogEventArgs(message)); } } // 使用示例 var logger = new LogSystem(); var analyzer = new Analyzer(); // 临时对象 logger.AddListener(analyzer.HandleLog); // 当analyzer超出作用域后,可被GC回收 </syntaxhighlight> == 数学原理 == 弱引用不影响对象可达性判定。设对象<math>O</math>的引用集合为<math>R</math>,当且仅当: <math> O \text{ 可达} \iff \exists r \in R \text{(强引用)}, r \rightarrow O </math> == 性能考量 == {| class="wikitable" |- ! 方案 !! 优点 !! 缺点 |- | WeakEventManager || 线程安全 || 依赖WPF库 |- | 手动实现 || 无外部依赖 || 需自行处理同步 |} == 最佳实践 == * 适用场景: * 长期存活对象监听短期对象 * 插件/模块化系统 * 避免场景: * 高频事件(弱引用有性能开销) * 必须严格保证调用顺序的场景 == 进阶主题 == === 泛型增强实现 === 支持任意委托类型的扩展方案: <syntaxhighlight lang="csharp"> public class WeakDelegate<TDelegate> where TDelegate : Delegate { private readonly WeakReference _target; private readonly MethodInfo _method; public WeakDelegate(TDelegate handler) { _target = new WeakReference(handler.Target); _method = handler.Method; } public TDelegate? CreateDelegate() { if (_target.Target != null) return (TDelegate)Delegate.CreateDelegate(typeof(TDelegate), _target.Target, _method); return null; } } </syntaxhighlight> == 常见问题 == '''Q: 弱事件会导致事件偶尔不触发吗?'''<br/> A: 会。当订阅者被回收后,对应事件将自动失效,这是设计预期行为。 '''Q: 如何调试弱事件相关问题?'''<br/> A: 建议: 1. 使用内存分析工具检查对象存活状态 2. 添加调试日志记录事件订阅/取消订阅 通过本文,您应已掌握弱事件模式的核心概念及实现方法。这种模式在特定场景下能有效改善内存管理,但需根据实际需求谨慎选用。 [[Category:编程语言]] [[Category:C Sharp]] [[Category:C Sharp 属性与事件]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)