diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/UniqueEventHelper.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/UniqueEventHelper.cs index 2a7e7c2b0bf..08e4b08cbea 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/UniqueEventHelper.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/UniqueEventHelper.cs @@ -2,8 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections; +using System.Collections.Generic; using System.Diagnostics; namespace System.Windows.Media @@ -17,62 +16,19 @@ namespace System.Windows.Media /// handlers that throw exceptions will crash the app, making the developer /// aware of the problem. /// - internal class UniqueEventHelper - where TEventArgs : EventArgs + internal sealed class UniqueEventHelper : UniqueEventHelperBase> + where TEventArgs : EventArgs { - /// - /// Add the handler to the list of handlers associated with this event. - /// If the handler has already been added, we simply increment the ref - /// count. That way if this same handler has already been added, it - /// won't be invoked multiple times when the event is raised. - /// - internal void AddEvent(EventHandler handler) - { - if (handler == null) - { - throw new System.ArgumentNullException("handler"); - } - - EnsureEventTable(); - - if (_htDelegates[handler] == null) - { - _htDelegates.Add(handler, 1); - } - else - { - int refCount = (int)_htDelegates[handler] + 1; - _htDelegates[handler] = refCount; - } - } - - /// - /// Removed the handler from the list of handlers associated with this - /// event. If the handler has been added multiple times (more times than - /// it has been removed), we simply decrement its ref count. - /// - internal void RemoveEvent(EventHandler handler) + /// Clones the event helper + internal UniqueEventHelper Clone() { - if (handler == null) + var ueh = new UniqueEventHelper(); + if (_delegates != null) { - throw new System.ArgumentNullException("handler"); + ueh._delegates = new Dictionary, int>(_delegates); } - EnsureEventTable(); - - if (_htDelegates[handler] != null) - { - int refCount = (int)_htDelegates[handler]; - - if (refCount == 1) - { - _htDelegates.Remove(handler); - } - else - { - _htDelegates[handler] = refCount - 1; - } - } + return ueh; } /// @@ -83,77 +39,68 @@ internal void RemoveEvent(EventHandler handler) /// The args object to be sent by the delegate internal void InvokeEvents(object sender, TEventArgs args) { - Debug.Assert((sender != null), "Sender is null"); - - if (_htDelegates != null) + Debug.Assert(sender != null, "Sender is null"); + foreach (EventHandler handler in CopyHandlers()) { - Hashtable htDelegates = (Hashtable)_htDelegates.Clone(); - foreach (EventHandler handler in htDelegates.Keys) - { - Debug.Assert((handler != null), "Event handler is null"); - handler(sender, args); - } + Debug.Assert(handler != null, "Event handler is null"); + handler(sender, args); } } + } - /// - /// Clones the event helper - /// - internal UniqueEventHelper Clone() + internal sealed class UniqueEventHelper : UniqueEventHelperBase + { + /// Clones the event helper + internal UniqueEventHelper Clone() { - UniqueEventHelper ueh = new UniqueEventHelper(); - if (_htDelegates != null) + var ueh = new UniqueEventHelper(); + if (_delegates != null) { - ueh._htDelegates = (Hashtable)_htDelegates.Clone(); + ueh._delegates = new Dictionary(_delegates); } + return ueh; } /// - /// Ensures Hashtable is created so that event handlers can be added/removed + /// Enumerates all the keys in the hashtable, which must be EventHandlers, + /// and invokes them. /// - private void EnsureEventTable() + /// The sender for the callback. + /// The args object to be sent by the delegate + internal void InvokeEvents(object sender, EventArgs args) { - if (_htDelegates == null) + Debug.Assert(sender != null, "Sender is null"); + foreach (EventHandler handler in CopyHandlers()) { - _htDelegates = new Hashtable(); + Debug.Assert(handler != null, "Event handler is null"); + handler(sender, args); } } - - private Hashtable _htDelegates; } - - - // (if possible) figure out a way so that the - // previous class can be used in place of this one. This class is needed - // in addition to the above generic one because EventHandler cannot be - // cast to its generic counterpart - internal class UniqueEventHelper + internal abstract class UniqueEventHelperBase where TEventHandler : Delegate { + protected Dictionary _delegates; + /// /// Add the handler to the list of handlers associated with this event. /// If the handler has already been added, we simply increment the ref /// count. That way if this same handler has already been added, it /// won't be invoked multiple times when the event is raised. /// - internal void AddEvent(EventHandler handler) + internal void AddEvent(TEventHandler handler) { - if (handler == null) - { - throw new System.ArgumentNullException("handler"); - } - - EnsureEventTable(); + ArgumentNullException.ThrowIfNull(handler); - if (_htDelegates[handler] == null) + if (_delegates is Dictionary delegates) { - _htDelegates.Add(handler, 1); + delegates.TryGetValue(handler, out int refCount); + delegates[handler] = refCount + 1; } else { - int refCount = (int)_htDelegates[handler] + 1; - _htDelegates[handler] = refCount; + _delegates = new Dictionary() { { handler, 1 } }; } } @@ -162,75 +109,34 @@ internal void AddEvent(EventHandler handler) /// event. If the handler has been added multiple times (more times than /// it has been removed), we simply decrement its ref count. /// - internal void RemoveEvent(EventHandler handler) + internal void RemoveEvent(TEventHandler handler) { - if (handler == null) - { - throw new System.ArgumentNullException("handler"); - } - - EnsureEventTable(); + ArgumentNullException.ThrowIfNull(handler); - if (_htDelegates[handler] != null) + if (_delegates is Dictionary delegates && + delegates.TryGetValue(handler, out int refCount)) { - int refCount = (int)_htDelegates[handler]; - if (refCount == 1) { - _htDelegates.Remove(handler); + delegates.Remove(handler); } else { - _htDelegates[handler] = refCount - 1; + delegates[handler] = refCount - 1; } } } - /// - /// Enumerates all the keys in the hashtable, which must be EventHandlers, - /// and invokes them. - /// - /// The sender for the callback. - /// The args object to be sent by the delegate - internal void InvokeEvents(object sender, EventArgs args) + protected TEventHandler[] CopyHandlers() { - Debug.Assert((sender != null), "Sender is null"); - - if (_htDelegates != null) + if (_delegates is { Count: > 0 } delegates) { - Hashtable htDelegates = (Hashtable)_htDelegates.Clone(); - foreach (EventHandler handler in htDelegates.Keys) - { - Debug.Assert((handler != null), "Event handler is null"); - handler(sender, args); - } + var handlers = new TEventHandler[delegates.Count]; + delegates.Keys.CopyTo(handlers, 0); + return handlers; } - } - /// - /// Clones the event helper - /// - internal UniqueEventHelper Clone() - { - UniqueEventHelper ueh = new UniqueEventHelper(); - if (_htDelegates != null) - { - ueh._htDelegates = (Hashtable)_htDelegates.Clone(); - } - return ueh; - } - - /// - /// Ensures Hashtable is created so that event handlers can be added/removed - /// - private void EnsureEventTable() - { - if (_htDelegates == null) - { - _htDelegates = new Hashtable(); - } + return Array.Empty(); } - - private Hashtable _htDelegates; } }