Skip to content

Commit f6881ae

Browse files
Merge pull request #136 from TimeWarpEngineering/Cramer-2019-05-15
Implement IDisposable on BaseComponent
2 parents a98f50b + 5936495 commit f6881ae

3 files changed

Lines changed: 77 additions & 37 deletions

File tree

Documentation/TemplateOverview.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
1-
## TimeWarp-Blazor Template
1+
# TimeWarp-Blazor Template
22

3-
### Installation
3+
## Installation
44

5-
```
5+
```console
66
dotnet new --install TimeWarp.AspNetCore.Blazor.Templates
77
```
88

9-
### Usage
9+
## Usage
1010

11-
```
11+
```console
1212
dotnet new timewarp-blazor -n MyBlazorApp
1313
```
1414

15-
### Projects
16-
MyBlazorApp.Client<br/>
17-
MyBlazorApp.Server<br/>
15+
## Projects
16+
17+
MyBlazorApp.Client
18+
MyBlazorApp.Server
1819
MyBlazorApp.Shared
1920

20-
### Test Projects
21-
MyBlazorApp.Client.Integration.Tests<br/>
22-
MyBlazorApp.Server.Integration.Tests<br/>
21+
## Test Projects
22+
23+
MyBlazorApp.Client.Integration.Tests
24+
MyBlazorApp.Server.Integration.Tests
2325
MyBlazorApp.EndToEnd.Tests

source/BlazorState/Components/BlazorStateComponent.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
/// And exposes StateHasChanged
1111
/// </summary>
1212
/// <remarks>Implements IBlazorStateComponent by Injecting</remarks>
13-
public class BlazorStateComponent : ComponentBase,
13+
public class BlazorStateComponent : ComponentBase, IDisposable,
1414
IBlazorStateComponent
1515
{
1616
static readonly ConcurrentDictionary<string, int> s_InstanceCounts = new ConcurrentDictionary<string, int>();
@@ -59,5 +59,7 @@ protected T GetState<T>()
5959
Subscriptions.Add(stateType, this);
6060
return Store.GetState<T>();
6161
}
62+
63+
public void Dispose() => Subscriptions.Remove(this);
6264
}
6365
}

source/BlazorState/Subscriptions.cs

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,41 @@
22
{
33
using System;
44
using System.Collections.Generic;
5+
using System.Linq;
56
using Microsoft.Extensions.Logging;
67

78
public class Subscriptions
89
{
10+
private readonly struct Subscription : IEquatable<Subscription>
11+
{
12+
public Subscription(Type aStateType, string aComponentId, WeakReference<BlazorStateComponent> aBlazorStateComponentReference)
13+
{
14+
StateType = aStateType;
15+
ComponentId = aComponentId;
16+
BlazorStateComponentReference = aBlazorStateComponentReference;
17+
}
18+
19+
public Type StateType { get; }
20+
public string ComponentId { get; }
21+
public WeakReference<BlazorStateComponent> BlazorStateComponentReference { get; }
22+
23+
public bool Equals(Subscription aSubscription) =>
24+
EqualityComparer<Type>.Default.Equals(StateType, aSubscription.StateType) &&
25+
ComponentId == aSubscription.ComponentId &&
26+
EqualityComparer<WeakReference<BlazorStateComponent>>.Default.Equals(BlazorStateComponentReference, aSubscription.BlazorStateComponentReference);
27+
28+
public static bool operator ==(Subscription aLeftSubscription, Subscription aRightSubscription) => aLeftSubscription.Equals(aRightSubscription);
29+
public static bool operator !=(Subscription aLeftSubscription, Subscription aRightSubscription) => !(aLeftSubscription == aRightSubscription);
30+
}
31+
932
public Subscriptions(ILogger<Subscriptions> aLogger)
1033
{
1134
Logger = aLogger;
12-
BlazorStateComponentReferencesDictionary = new Dictionary<Type, List<WeakReference<BlazorStateComponent>>>();
35+
BlazorStateComponentReferencesList = new List<Subscription>();
1336
}
1437

1538
private ILogger Logger { get; }
16-
private Dictionary<Type, List<WeakReference<BlazorStateComponent>>> BlazorStateComponentReferencesDictionary { get; }
39+
private List<Subscription> BlazorStateComponentReferencesList { get; }
1740

1841
public Subscriptions Add<T>(BlazorStateComponent aBlazorStateComponent)
1942
{
@@ -23,18 +46,27 @@ public Subscriptions Add<T>(BlazorStateComponent aBlazorStateComponent)
2346
}
2447
public Subscriptions Add(Type aType, BlazorStateComponent aBlazorStateComponent)
2548
{
26-
27-
if (!(BlazorStateComponentReferencesDictionary.TryGetValue(aType, out List<WeakReference<BlazorStateComponent>> blazorStateComponentReferences)))
49+
// Add only once.
50+
if (!BlazorStateComponentReferencesList.Any(aSubscription => aSubscription.StateType == aType && aSubscription.ComponentId == aBlazorStateComponent.Id))
2851
{
29-
blazorStateComponentReferences = new List<WeakReference<BlazorStateComponent>>();
30-
BlazorStateComponentReferencesDictionary.Add(aType, blazorStateComponentReferences);
31-
}
52+
var subscription = new Subscription(
53+
aType,
54+
aBlazorStateComponent.Id,
55+
new WeakReference<BlazorStateComponent>(aBlazorStateComponent));
3256

33-
blazorStateComponentReferences.Add(new WeakReference<BlazorStateComponent>(aBlazorStateComponent));
57+
BlazorStateComponentReferencesList.Add(subscription);
58+
}
3459

3560
return this;
3661
}
3762

63+
public Subscriptions Remove(BlazorStateComponent aBlazorStateComponent)
64+
{
65+
Logger.LogDebug($"Removing Subscription for {aBlazorStateComponent.Id}");
66+
BlazorStateComponentReferencesList.RemoveAll(aRecord => aRecord.ComponentId == aBlazorStateComponent.Id);
67+
68+
return this;
69+
}
3870
/// <summary>
3971
/// Will iterate over all subscriptions for the given type and call ReRender on each.
4072
/// If the target component no longer exists it will remove its subscription.
@@ -54,27 +86,31 @@ public void ReRenderSubscribers<T>()
5486
/// <param name="aType"></param>
5587
public void ReRenderSubscribers(Type aType)
5688
{
57-
//GC.Collect(); // I added the collect to test that I am not holding strong references and they were collected.
58-
bool isAny = BlazorStateComponentReferencesDictionary.TryGetValue(aType, out List<WeakReference<BlazorStateComponent>> blazorStateblazorStateComponentReferencesComponents);
59-
if (isAny)
89+
IEnumerable<Subscription> subscriptions = BlazorStateComponentReferencesList.Where(aRecord => aRecord.StateType == aType);
90+
foreach (Subscription subscription in subscriptions)
6091
{
61-
Logger.LogDebug($"ReRendering {blazorStateblazorStateComponentReferencesComponents.Count} Subscribers for state of type: {aType.Name}");
62-
WeakReference<BlazorStateComponent>[] blazorStateComponentReferencesArray = blazorStateblazorStateComponentReferencesComponents.ToArray();
63-
64-
foreach (WeakReference<BlazorStateComponent> aBlazorStateComponentReference in blazorStateComponentReferencesArray)
92+
if (subscription.BlazorStateComponentReference.TryGetTarget(out BlazorStateComponent target))
6593
{
66-
if (aBlazorStateComponentReference.TryGetTarget(out BlazorStateComponent target))
67-
{
68-
Logger.LogDebug($"ReRender: {target.GetType().Name}");
69-
target.ReRender();
70-
}
71-
else
72-
{
73-
Logger.LogDebug($"Removing subscription to previously destroyed component.");
74-
blazorStateblazorStateComponentReferencesComponents.Remove(aBlazorStateComponentReference);
75-
}
94+
Logger.LogDebug($"ReRender: {target.GetType().Name}");
95+
target.ReRender();
96+
}
97+
else
98+
{
99+
// If Dispose is called will I ever have items in this list that got Garbage collected?
100+
// Maybe for those that don't inherit from our BaseComponent.
101+
BlazorStateComponentReferencesList.Remove(subscription);
76102
}
77103
}
78104
}
105+
106+
public override bool Equals(object obj) => obj is Subscriptions subscriptions && EqualityComparer<ILogger>.Default.Equals(Logger, subscriptions.Logger) && EqualityComparer<List<Subscription>>.Default.Equals(BlazorStateComponentReferencesList, subscriptions.BlazorStateComponentReferencesList);
107+
108+
public override int GetHashCode()
109+
{
110+
var hashCode = -914156548;
111+
hashCode = hashCode * -1521134295 + EqualityComparer<ILogger>.Default.GetHashCode(Logger);
112+
hashCode = hashCode * -1521134295 + EqualityComparer<List<Subscription>>.Default.GetHashCode(BlazorStateComponentReferencesList);
113+
return hashCode;
114+
}
79115
}
80116
}

0 commit comments

Comments
 (0)