订阅Singleton类发布的事件

我有一个名为CacheState的Singleton类。 这个类发布了很多事件。 CacheState有一个System.Timers.Timer,它循环并触发所有这些事件。

然后在我的asp.net应用程序中,我在Application_Start期间订阅了这些事件。 CacheState中的Timer也在此期间启动:

protected void Application_Start(object sender, EventArgs e) { CacheState.Instance.ProductChangedEvent += (objSender, argsE) => ProductService.ReloadProductCache(false); CacheState.Instance.PageflexChangedEvent += (objSender, argsE) => ProductService.ResetPageflexCache(false); CacheState.Instance.DeliveryChangedEvent += (objSender, argsE) => PricingRuleService.ResetDeliveryMethodsCache(false); CacheState.Instance.UIItemChangedEvent += (objSender, argsE) => TemplateService.ResetUIItemsCache(false); CacheState.Instance.ProductAttributeChangedEvent += Instance_ProductAttributeChangedEvent; CacheState.Instance.Start(); } 

我读过C#Events会导致内存泄漏。 那么,任何人都可以告诉我,如果我做错了吗?

谢谢。

单例实例包含对已订阅其事件的所有对象的引用。 如果这些对象不像单例实例那样存活, 并且它们不会取消订阅这些事件,那么它们将保留在内存中。 当您遇到内存泄漏时,这是唯一的情况。 显然,如果事件源在您的侦听器之前被释放,则引用将被清除,如果您正确取消注册侦听器,则还没有引用。

要解决此问题,您可以实现弱事件模式或在所有侦听单例事件的对象中实现例如IDisposable确保它们在代码中正确处理!

当然,这不仅适用于单例对象,也适用于任何充当事件源的对象。 然而,单例事件源是一个特别危险的情况,因为它通常只要您的应用程序运行就会存在,因此至少与任何其他对象一样长。

如果您通过代码多次分配给事件,C#可能会导致内存泄漏。 这可能发生在复杂的代码中,通常与初学者有关。 因此,您的eventhandler将被执行多次。

避免这种情况的一种正确方法是在附加事件(+ =)之前分离事件( – =),最好将其封装到管理该事件的方法中。

这可以确保指向事件处理方法的事件堆栈只填充一个条目(如果需要)。

这是我对内存泄漏了解的一件事。

另一件事是参考。 如果您的事件处理程序访问全局对象,或全局对象列表并插入值,并且您没有跟踪,则事件处理程序将导致全局变量被实例化,使用,引用等。 但这取决于设计。

如果有人知道更多,我会很感激。

  // generic delegate for genric events public delegate void EventsHandler(TArgs args) where TArgs : EventArgs; // generic singleton public abstract class EventsBase where TEvents : class, new() { private static readonly object lockObject = new object(); private static volatile TEvents instance; public static TEvents Instance { get { if (instance == null) { lock (lockObject) { if (instance == null) { instance = new TEvents(); } } } return instance; } } } public class EventArgs : EventArgs { public T Item { get; set; } public EventArgs(T item) { Item = item; } } public class MyEvents : EventsBase { public event EventsHandler>> OnCheckedDataBase; public event EventsHandler>> OnProcessedData; public void CheckedDataBase(IList handler) { if (OnCheckedDataBase != null) { OnCheckedDataBase(new EventArgs>(handler)); } } public void ProcessedData(IList handler) { if (OnProcessedData != null) { OnProcessedData(new EventArgs>(handler)); } } } MyEvents.Instance.OnCheckedDataBase += OnCheckedDataBase; //register MyEvents.Instance.CheckedDataBase(this); //fire