3
3
4
4
using System . Collections . Generic ;
5
5
using System . Diagnostics ;
6
+ using System . Threading ;
6
7
using System . Reflection ;
7
8
8
9
namespace System . Runtime . InteropServices
@@ -99,7 +100,7 @@ private void PreProcessSignature()
99
100
/// Since multicast delegate's built-in chaining supports only chaining instances of the same type,
100
101
/// we need to complement this design by using an explicit linked list data structure.
101
102
/// </summary>
102
- private readonly List < DelegateWrapper > _delegateWrappers = new List < DelegateWrapper > ( ) ;
103
+ private DelegateWrapper [ ] _delegateWrappers = Array . Empty < DelegateWrapper > ( ) ;
103
104
104
105
private readonly int _dispid ;
105
106
private ComEventsMethod ? _next ;
@@ -154,48 +155,36 @@ public static ComEventsMethod Add(ComEventsMethod? methods, ComEventsMethod meth
154
155
155
156
public bool Empty
156
157
{
157
- get
158
- {
159
- lock ( _delegateWrappers )
160
- {
161
- return _delegateWrappers . Count == 0 ;
162
- }
163
- }
158
+ get => _delegateWrappers . Length == 0 ;
164
159
}
165
160
166
161
public void AddDelegate ( Delegate d , bool wrapArgs = false )
167
162
{
168
- lock ( _delegateWrappers )
163
+ DelegateWrapper [ ] wrappers , newWrappers ;
164
+ do
169
165
{
170
- // Update an existing delegate wrapper
171
- foreach ( DelegateWrapper wrapper in _delegateWrappers )
172
- {
173
- if ( wrapper . Delegate . GetType ( ) == d . GetType ( ) && wrapper . WrapArgs == wrapArgs )
174
- {
175
- wrapper . Delegate = Delegate . Combine ( wrapper . Delegate , d ) ;
176
- return ;
177
- }
178
- }
179
-
180
- var newWrapper = new DelegateWrapper ( d , wrapArgs ) ;
181
- _delegateWrappers . Add ( newWrapper ) ;
182
- }
166
+ wrappers = _delegateWrappers ;
167
+ newWrappers = new DelegateWrapper [ wrappers . Length + 1 ] ;
168
+ wrappers . CopyTo ( newWrappers , 0 ) ;
169
+ newWrappers [ ^ 1 ] = new DelegateWrapper ( d , wrapArgs ) ;
170
+ } while ( ! PublishNewWrappers ( newWrappers , wrappers ) ) ;
183
171
}
184
172
185
173
public void RemoveDelegate ( Delegate d , bool wrapArgs = false )
186
174
{
187
- lock ( _delegateWrappers )
175
+ DelegateWrapper [ ] wrappers , newWrappers ;
176
+ do
188
177
{
178
+ wrappers = _delegateWrappers ;
179
+
189
180
// Find delegate wrapper index
190
181
int removeIdx = - 1 ;
191
- DelegateWrapper ? wrapper = null ;
192
- for ( int i = 0 ; i < _delegateWrappers . Count ; i ++ )
182
+ for ( int i = 0 ; i < wrappers . Length ; i ++ )
193
183
{
194
- DelegateWrapper wrapperMaybe = _delegateWrappers [ i ] ;
195
- if ( wrapperMaybe . Delegate . GetType ( ) == d . GetType ( ) && wrapperMaybe . WrapArgs == wrapArgs )
184
+ DelegateWrapper wrapperMaybe = wrappers [ i ] ;
185
+ if ( wrapperMaybe . Delegate == d && wrapperMaybe . WrapArgs == wrapArgs )
196
186
{
197
187
removeIdx = i ;
198
- wrapper = wrapperMaybe ;
199
188
break ;
200
189
}
201
190
}
@@ -206,67 +195,42 @@ public void RemoveDelegate(Delegate d, bool wrapArgs = false)
206
195
return ;
207
196
}
208
197
209
- // Update wrapper or remove from collection
210
- Delegate ? newDelegate = Delegate . Remove ( wrapper ! . Delegate , d ) ;
211
- if ( newDelegate != null )
212
- {
213
- wrapper . Delegate = newDelegate ;
214
- }
215
- else
216
- {
217
- _delegateWrappers . RemoveAt ( removeIdx ) ;
218
- }
219
- }
198
+ newWrappers = new DelegateWrapper [ wrappers . Length - 1 ] ;
199
+ wrappers . AsSpan ( 0 , removeIdx ) . CopyTo ( newWrappers ) ;
200
+ wrappers . AsSpan ( removeIdx + 1 ) . CopyTo ( newWrappers . AsSpan ( removeIdx ) ) ;
201
+ } while ( ! PublishNewWrappers ( newWrappers , wrappers ) ) ;
220
202
}
221
203
222
204
public void RemoveDelegates ( Func < Delegate , bool > condition )
223
205
{
224
- lock ( _delegateWrappers )
206
+ DelegateWrapper [ ] wrappers , newWrappers ;
207
+ do
225
208
{
226
- // Find delegate wrapper indexes. Iterate in reverse such that the list to remove is sorted by high to low index.
227
- List < int > toRemove = new List < int > ( ) ;
228
- for ( int i = _delegateWrappers . Count - 1 ; i >= 0 ; i -- )
229
- {
230
- DelegateWrapper wrapper = _delegateWrappers [ i ] ;
231
- Delegate [ ] invocationList = wrapper . Delegate . GetInvocationList ( ) ;
232
- foreach ( Delegate delegateMaybe in invocationList )
233
- {
234
- if ( condition ( delegateMaybe ) )
235
- {
236
- Delegate ? newDelegate = Delegate . Remove ( wrapper ! . Delegate , delegateMaybe ) ;
237
- if ( newDelegate != null )
238
- {
239
- wrapper . Delegate = newDelegate ;
240
- }
241
- else
242
- {
243
- toRemove . Add ( i ) ;
244
- }
245
- }
246
- }
247
- }
248
-
249
- foreach ( int idx in toRemove )
250
- {
251
- _delegateWrappers . RemoveAt ( idx ) ;
252
- }
209
+ wrappers = _delegateWrappers ;
210
+ List < DelegateWrapper > tmp = new ( wrappers ) ;
211
+ tmp . RemoveAll ( w => condition ( w . Delegate ) ) ;
212
+ newWrappers = tmp . ToArray ( ) ;
253
213
}
214
+ while ( ! PublishNewWrappers ( newWrappers , wrappers ) ) ;
254
215
}
255
216
256
217
public object ? Invoke ( object [ ] args )
257
218
{
258
219
Debug . Assert ( ! Empty ) ;
259
220
object ? result = null ;
260
221
261
- lock ( _delegateWrappers )
222
+ foreach ( DelegateWrapper wrapper in _delegateWrappers )
262
223
{
263
- foreach ( DelegateWrapper wrapper in _delegateWrappers )
264
- {
265
- result = wrapper . Invoke ( args ) ;
266
- }
224
+ result = wrapper . Invoke ( args ) ;
267
225
}
268
226
269
227
return result ;
270
228
}
229
+
230
+ // Attempt to update the member wrapper field
231
+ private bool PublishNewWrappers ( DelegateWrapper [ ] newWrappers , DelegateWrapper [ ] currentMaybe )
232
+ {
233
+ return Interlocked . CompareExchange ( ref _delegateWrappers , newWrappers , currentMaybe ) == currentMaybe ;
234
+ }
271
235
}
272
236
}
0 commit comments