@@ -12,18 +12,16 @@ namespace Microsoft.AspNetCore.Components.Rendering
12
12
/// Provides mechanisms for rendering hierarchies of <see cref="IComponent"/> instances,
13
13
/// dispatching events to them, and notifying when the user interface is being updated.
14
14
/// </summary>
15
- public abstract class Renderer
15
+ public abstract class Renderer : IDisposable
16
16
{
17
17
private readonly ComponentFactory _componentFactory ;
18
- private int _nextComponentId = 0 ; // TODO: change to 'long' when Mono .NET->JS interop supports it
19
- private readonly Dictionary < int , ComponentState > _componentStateById
20
- = new Dictionary < int , ComponentState > ( ) ;
21
-
18
+ private readonly Dictionary < int , ComponentState > _componentStateById = new Dictionary < int , ComponentState > ( ) ;
22
19
private readonly RenderBatchBuilder _batchBuilder = new RenderBatchBuilder ( ) ;
23
- private bool _isBatchInProgress ;
20
+ private readonly Dictionary < int , EventHandlerInvoker > _eventBindings = new Dictionary < int , EventHandlerInvoker > ( ) ;
24
21
22
+ private int _nextComponentId = 0 ; // TODO: change to 'long' when Mono .NET->JS interop supports it
23
+ private bool _isBatchInProgress ;
25
24
private int _lastEventHandlerId = 0 ;
26
- private readonly Dictionary < int , EventHandlerInvoker > _eventBindings = new Dictionary < int , EventHandlerInvoker > ( ) ;
27
25
28
26
/// <summary>
29
27
/// Constructs an instance of <see cref="Renderer"/>.
@@ -175,7 +173,7 @@ internal void AssignEventHandlerId(ref RenderTreeFrame frame)
175
173
176
174
if ( frame . AttributeValue is MulticastDelegate @delegate )
177
175
{
178
- _eventBindings . Add ( id , new EventHandlerInvoker ( @delegate ) ) ;
176
+ _eventBindings . Add ( id , new EventHandlerInvoker ( @delegate ) ) ;
179
177
}
180
178
181
179
frame = frame . WithAttributeEventHandlerId ( id ) ;
@@ -295,5 +293,44 @@ private void RemoveEventHandlerIds(ArrayRange<int> eventHandlerIds, Task afterTa
295
293
RemoveEventHandlerIds ( eventHandlerIdsClone , Task . CompletedTask ) ) ;
296
294
}
297
295
}
296
+
297
+ /// <summary>
298
+ /// Releases all resources currently used by this <see cref="Renderer"/> instance.
299
+ /// </summary>
300
+ /// <param name="disposing"><see langword="true"/> if this method is being invoked by <see cref="IDisposable.Dispose"/>, otherwise <see langword="false"/>.</param>
301
+ protected virtual void Dispose ( bool disposing )
302
+ {
303
+ List < Exception > exceptions = null ;
304
+
305
+ foreach ( var componentState in _componentStateById . Values )
306
+ {
307
+ if ( componentState . Component is IDisposable disposable )
308
+ {
309
+ try
310
+ {
311
+ disposable . Dispose ( ) ;
312
+ }
313
+ catch ( Exception exception )
314
+ {
315
+ // Capture exceptions thrown by individual components and rethrow as an aggregate.
316
+ exceptions = exceptions ?? new List < Exception > ( ) ;
317
+ exceptions . Add ( exception ) ;
318
+ }
319
+ }
320
+ }
321
+
322
+ if ( exceptions != null )
323
+ {
324
+ throw new AggregateException ( exceptions ) ;
325
+ }
326
+ }
327
+
328
+ /// <summary>
329
+ /// Releases all resources currently used by this <see cref="Renderer"/> instance.
330
+ /// </summary>
331
+ public void Dispose ( )
332
+ {
333
+ Dispose ( disposing : true ) ;
334
+ }
298
335
}
299
336
}
0 commit comments