22// The .NET Foundation licenses this file to you under the MIT license.
33// See the LICENSE file in the project root for more information.
44
5- using System ;
6- using System . Collections ;
5+ using System . Collections . Generic ;
76using System . Diagnostics ;
87
98namespace System . Windows . Media
@@ -17,62 +16,19 @@ namespace System.Windows.Media
1716 /// handlers that throw exceptions will crash the app, making the developer
1817 /// aware of the problem.
1918 /// </summary>
20- internal class UniqueEventHelper < TEventArgs >
21- where TEventArgs : EventArgs
19+ internal sealed class UniqueEventHelper < TEventArgs > : UniqueEventHelperBase < EventHandler < TEventArgs > >
20+ where TEventArgs : EventArgs
2221 {
23- /// <summary>
24- /// Add the handler to the list of handlers associated with this event.
25- /// If the handler has already been added, we simply increment the ref
26- /// count. That way if this same handler has already been added, it
27- /// won't be invoked multiple times when the event is raised.
28- /// </summary>
29- internal void AddEvent ( EventHandler < TEventArgs > handler )
30- {
31- if ( handler == null )
32- {
33- throw new System . ArgumentNullException ( "handler" ) ;
34- }
35-
36- EnsureEventTable ( ) ;
37-
38- if ( _htDelegates [ handler ] == null )
39- {
40- _htDelegates . Add ( handler , 1 ) ;
41- }
42- else
43- {
44- int refCount = ( int ) _htDelegates [ handler ] + 1 ;
45- _htDelegates [ handler ] = refCount ;
46- }
47- }
48-
49- /// <summary>
50- /// Removed the handler from the list of handlers associated with this
51- /// event. If the handler has been added multiple times (more times than
52- /// it has been removed), we simply decrement its ref count.
53- /// </summary>
54- internal void RemoveEvent ( EventHandler < TEventArgs > handler )
22+ /// <summary>Clones the event helper</summary>
23+ internal UniqueEventHelper < TEventArgs > Clone ( )
5524 {
56- if ( handler == null )
25+ var ueh = new UniqueEventHelper < TEventArgs > ( ) ;
26+ if ( _delegates != null )
5727 {
58- throw new System . ArgumentNullException ( "handler" ) ;
28+ ueh . _delegates = new Dictionary < EventHandler < TEventArgs > , int > ( _delegates ) ;
5929 }
6030
61- EnsureEventTable ( ) ;
62-
63- if ( _htDelegates [ handler ] != null )
64- {
65- int refCount = ( int ) _htDelegates [ handler ] ;
66-
67- if ( refCount == 1 )
68- {
69- _htDelegates . Remove ( handler ) ;
70- }
71- else
72- {
73- _htDelegates [ handler ] = refCount - 1 ;
74- }
75- }
31+ return ueh ;
7632 }
7733
7834 /// <summary>
@@ -83,77 +39,68 @@ internal void RemoveEvent(EventHandler<TEventArgs> handler)
8339 /// <param name="args">The args object to be sent by the delegate</param>
8440 internal void InvokeEvents ( object sender , TEventArgs args )
8541 {
86- Debug . Assert ( ( sender != null ) , "Sender is null" ) ;
87-
88- if ( _htDelegates != null )
42+ Debug . Assert ( sender != null , "Sender is null" ) ;
43+ foreach ( EventHandler < TEventArgs > handler in CopyHandlers ( ) )
8944 {
90- Hashtable htDelegates = ( Hashtable ) _htDelegates . Clone ( ) ;
91- foreach ( EventHandler < TEventArgs > handler in htDelegates . Keys )
92- {
93- Debug . Assert ( ( handler != null ) , "Event handler is null" ) ;
94- handler ( sender , args ) ;
95- }
45+ Debug . Assert ( handler != null , "Event handler is null" ) ;
46+ handler ( sender , args ) ;
9647 }
9748 }
49+ }
9850
99- /// <summary >
100- /// Clones the event helper
101- /// </summary>
102- internal UniqueEventHelper < TEventArgs > Clone ( )
51+ internal sealed class UniqueEventHelper : UniqueEventHelperBase < EventHandler >
52+ {
53+ /// <summary>Clones the event helper< /summary>
54+ internal UniqueEventHelper Clone ( )
10355 {
104- UniqueEventHelper < TEventArgs > ueh = new UniqueEventHelper < TEventArgs > ( ) ;
105- if ( _htDelegates != null )
56+ var ueh = new UniqueEventHelper ( ) ;
57+ if ( _delegates != null )
10658 {
107- ueh . _htDelegates = ( Hashtable ) _htDelegates . Clone ( ) ;
59+ ueh . _delegates = new Dictionary < EventHandler , int > ( _delegates ) ;
10860 }
61+
10962 return ueh ;
11063 }
11164
11265 /// <summary>
113- /// Ensures Hashtable is created so that event handlers can be added/removed
66+ /// Enumerates all the keys in the hashtable, which must be EventHandlers,
67+ /// and invokes them.
11468 /// </summary>
115- private void EnsureEventTable ( )
69+ /// <param name="sender">The sender for the callback.</param>
70+ /// <param name="args">The args object to be sent by the delegate</param>
71+ internal void InvokeEvents ( object sender , EventArgs args )
11672 {
117- if ( _htDelegates == null )
73+ Debug . Assert ( sender != null , "Sender is null" ) ;
74+ foreach ( EventHandler handler in CopyHandlers ( ) )
11875 {
119- _htDelegates = new Hashtable ( ) ;
76+ Debug . Assert ( handler != null , "Event handler is null" ) ;
77+ handler ( sender , args ) ;
12078 }
12179 }
122-
123- private Hashtable _htDelegates ;
12480 }
12581
126-
127-
128- // (if possible) figure out a way so that the
129- // previous class can be used in place of this one. This class is needed
130- // in addition to the above generic one because EventHandler cannot be
131- // cast to its generic counterpart
132- internal class UniqueEventHelper
82+ internal abstract class UniqueEventHelperBase < TEventHandler > where TEventHandler : Delegate
13383 {
84+ protected Dictionary < TEventHandler , int > _delegates ;
85+
13486 /// <summary>
13587 /// Add the handler to the list of handlers associated with this event.
13688 /// If the handler has already been added, we simply increment the ref
13789 /// count. That way if this same handler has already been added, it
13890 /// won't be invoked multiple times when the event is raised.
13991 /// </summary>
140- internal void AddEvent ( EventHandler handler )
92+ internal void AddEvent ( TEventHandler handler )
14193 {
142- if ( handler == null )
143- {
144- throw new System . ArgumentNullException ( "handler" ) ;
145- }
146-
147- EnsureEventTable ( ) ;
94+ ArgumentNullException . ThrowIfNull ( handler ) ;
14895
149- if ( _htDelegates [ handler ] == null )
96+ if ( _delegates is Dictionary < TEventHandler , int > delegates )
15097 {
151- _htDelegates . Add ( handler , 1 ) ;
98+ delegates . TryGetValue ( handler , out int refCount ) ;
99+ delegates [ handler ] = refCount + 1 ;
152100 }
153101 else
154102 {
155- int refCount = ( int ) _htDelegates [ handler ] + 1 ;
156- _htDelegates [ handler ] = refCount ;
103+ _delegates = new Dictionary < TEventHandler , int > ( ) { { handler , 1 } } ;
157104 }
158105 }
159106
@@ -162,75 +109,34 @@ internal void AddEvent(EventHandler handler)
162109 /// event. If the handler has been added multiple times (more times than
163110 /// it has been removed), we simply decrement its ref count.
164111 /// </summary>
165- internal void RemoveEvent ( EventHandler handler )
112+ internal void RemoveEvent ( TEventHandler handler )
166113 {
167- if ( handler == null )
168- {
169- throw new System . ArgumentNullException ( "handler" ) ;
170- }
171-
172- EnsureEventTable ( ) ;
114+ ArgumentNullException . ThrowIfNull ( handler ) ;
173115
174- if ( _htDelegates [ handler ] != null )
116+ if ( _delegates is Dictionary < TEventHandler , int > delegates &&
117+ delegates . TryGetValue ( handler , out int refCount ) )
175118 {
176- int refCount = ( int ) _htDelegates [ handler ] ;
177-
178119 if ( refCount == 1 )
179120 {
180- _htDelegates . Remove ( handler ) ;
121+ delegates . Remove ( handler ) ;
181122 }
182123 else
183124 {
184- _htDelegates [ handler ] = refCount - 1 ;
125+ delegates [ handler ] = refCount - 1 ;
185126 }
186127 }
187128 }
188129
189- /// <summary>
190- /// Enumerates all the keys in the hashtable, which must be EventHandlers,
191- /// and invokes them.
192- /// </summary>
193- /// <param name="sender">The sender for the callback.</param>
194- /// <param name="args">The args object to be sent by the delegate</param>
195- internal void InvokeEvents ( object sender , EventArgs args )
130+ protected TEventHandler [ ] CopyHandlers ( )
196131 {
197- Debug . Assert ( ( sender != null ) , "Sender is null" ) ;
198-
199- if ( _htDelegates != null )
132+ if ( _delegates is { Count : > 0 } delegates )
200133 {
201- Hashtable htDelegates = ( Hashtable ) _htDelegates . Clone ( ) ;
202- foreach ( EventHandler handler in htDelegates . Keys )
203- {
204- Debug . Assert ( ( handler != null ) , "Event handler is null" ) ;
205- handler ( sender , args ) ;
206- }
134+ var handlers = new TEventHandler [ delegates . Count ] ;
135+ delegates . Keys . CopyTo ( handlers , 0 ) ;
136+ return handlers ;
207137 }
208- }
209138
210- /// <summary>
211- /// Clones the event helper
212- /// </summary>
213- internal UniqueEventHelper Clone ( )
214- {
215- UniqueEventHelper ueh = new UniqueEventHelper ( ) ;
216- if ( _htDelegates != null )
217- {
218- ueh . _htDelegates = ( Hashtable ) _htDelegates . Clone ( ) ;
219- }
220- return ueh ;
221- }
222-
223- /// <summary>
224- /// Ensures Hashtable is created so that event handlers can be added/removed
225- /// </summary>
226- private void EnsureEventTable ( )
227- {
228- if ( _htDelegates == null )
229- {
230- _htDelegates = new Hashtable ( ) ;
231- }
139+ return Array . Empty < TEventHandler > ( ) ;
232140 }
233-
234- private Hashtable _htDelegates ;
235141 }
236142}
0 commit comments