更新:我编写了一个程序来测试我在下面提到的每种技术的内存影响。毫不奇怪,我发现,果然,使用 .NET 事件的传统方法比其他方法产生更多的垃圾(意思是,它确实会产生垃圾,而其他两种策略似乎都不会产生任何垃圾)。
真的,我应该一直强调,我对.NET 事件中参数的内存开销比速度方面的成本更感兴趣。最终我不得不承认,就所有实际目的而言——无论是内存还是速度——成本都可以忽略不计。尽管如此,我还是觉得有趣的是,以“传统”方式引发大量事件确实会花费一些东西——而且在极端情况下,它甚至会导致第一代垃圾收集,这可能会或可能无关紧要,具体取决于情况(根据我的经验,系统需要越“实时”,就越需要注意垃圾的产生位置以及如何在适当的情况下将其最小化)。TEventArgs
这似乎是一个愚蠢的问题。例如,我意识到 Windows 窗体可以很容易地被认为是“高性能”场景,数百甚至数千个事件一直在非常快速地连续引发(例如,Control.MouseMove
事件)。但我仍然想知道,当预期该类将用于高性能、时间关键的代码时,使用 .NET 事件设计一个类是否真的合理。
我主要关心的是一个约定,即EventHandler<TEventArgs>
对所有事件都使用类似的东西,其中TEventArgs
派生自EventArgs
并且很可能是每次引发/处理事件时都必须实例化的类。(如果它只是 plain EventsArgs
,显然,这不是EventArgs.Empty
可以使用的情况;但假设类型中包含任何有意义和非常量的信息TEventArgs
,则可能需要实例化。)看起来这会导致 GC 压力大于我希望创建一个高性能库。
也就是说,我能想到的唯一选择是:
- 对事件使用非常规的委托类型(即 not
EventHandler<TEventArgs>
),仅采用不需要对象实例化的参数,例如int
,double
等(甚至string
, 并传递对现有字符串对象的引用)。 - 完全跳过事件并使用虚拟方法,强制客户端代码根据需要覆盖它们。这似乎与之前的想法具有基本相同的效果,但方式更加可控。
我对 .NET 事件的 GC 压力的担忧一开始就没有根据吗?如果是这样,我在那里错过了什么?或者,有没有比我刚刚列出的两个更好的第三种选择?