diff --git a/Hyperbar/Hyperbar.csproj b/Hyperbar/Hyperbar.csproj index c55732b..acc8244 100644 --- a/Hyperbar/Hyperbar.csproj +++ b/Hyperbar/Hyperbar.csproj @@ -7,5 +7,6 @@ + diff --git a/Hyperbar/Lifecycles/AppService.cs b/Hyperbar/Lifecycles/AppService.cs index 07d318a..ce7e39d 100644 --- a/Hyperbar/Lifecycles/AppService.cs +++ b/Hyperbar/Lifecycles/AppService.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Hosting; +using System; namespace Hyperbar; diff --git a/Hyperbar/Lifecycles/Disposer.cs b/Hyperbar/Lifecycles/Disposer.cs new file mode 100644 index 0000000..6759ba0 --- /dev/null +++ b/Hyperbar/Lifecycles/Disposer.cs @@ -0,0 +1,81 @@ +using System.Runtime.CompilerServices; +using System.Reactive.Disposables; +using System.Collections; + +namespace Hyperbar; + +public class Disposer : + IDisposer +{ + private readonly ConditionalWeakTable subjects = []; + + public void Add(object subject, + params object[] objects) + { + CompositeDisposable disposables = subjects.GetOrCreateValue(subject); + foreach (IDisposable disposable in objects.OfType()) + { + disposables.Add(disposable); + } + + foreach (object notDisposable in objects.Where(x => x is not IDisposable)) + { + disposables.Add(Disposable.Create(() => FromNotDisposable(notDisposable))); + } + } + + private void FromNotDisposable(object target) + { + if (target is IEnumerable enumerableTarget) + { + foreach (object? item in enumerableTarget) + { + FromNotDisposable(item); + } + } + + if (target is IDisposable disposableTarget) + { + disposableTarget.Dispose(); + } + + if (target is not IDisposable) + { + Dispose(target); + } + } + + public TDisposable Replace(object subject, + IDisposable disposer, + TDisposable replacement) + where TDisposable : + IDisposable + { + CompositeDisposable disposables = subjects.GetOrCreateValue(subject); + if (disposer is not null) + { + disposables.Remove(disposer); + } + + disposables.Add(replacement); + return replacement; + } + + public void Remove(object subject, + IDisposable disposer) + { + CompositeDisposable disposables = subjects.GetOrCreateValue(subject); + if (disposer is not null) + { + disposables.Remove(disposer); + } + } + + public void Dispose(object subject) + { + if (subjects.TryGetValue(subject, out CompositeDisposable? disposables)) + { + disposables?.Dispose(); + } + } +} diff --git a/Hyperbar/Lifecycles/IDisposer.cs b/Hyperbar/Lifecycles/IDisposer.cs new file mode 100644 index 0000000..0744dba --- /dev/null +++ b/Hyperbar/Lifecycles/IDisposer.cs @@ -0,0 +1,16 @@ +namespace Hyperbar; + +public interface IDisposer +{ + void Add(object subject, + params object[] objects); + + TDisposable Replace(object subject, + IDisposable disposer, + TDisposable replacement) where TDisposable : IDisposable; + + void Remove(object subject, + IDisposable disposer); + + void Dispose(object subject); +} \ No newline at end of file diff --git a/Hyperbar/Mediators/Mediator.cs b/Hyperbar/Mediators/Mediator.cs index 3a29aeb..c095f72 100644 --- a/Hyperbar/Mediators/Mediator.cs +++ b/Hyperbar/Mediators/Mediator.cs @@ -6,7 +6,7 @@ namespace Hyperbar; public class Mediator(IServiceProvider provider) : IMediator { - private readonly List> addedHandlers = []; + private readonly ConditionalWeakTable subjects = []; public ValueTask PublishAsync(TNotification notification, CancellationToken cancellationToken = default) @@ -16,11 +16,11 @@ public class Mediator(IServiceProvider provider) : List> handlers = provider.GetServices>().ToList(); - foreach (KeyValuePair handler in addedHandlers) + foreach (KeyValuePair handler in subjects) { - if (handler.Key == typeof(TNotification)) + if (handler.Value == typeof(TNotification)) { - handlers.Add(handler.Value); + handlers.Add(handler.Key); } } @@ -78,7 +78,7 @@ public class Mediator(IServiceProvider provider) : if (interfaceType.GetGenericArguments() is { Length: 1 } arguments) { Type notificationType = arguments[0]; - addedHandlers.Add(new KeyValuePair(notificationType, subject)); + subjects.Add(subject, notificationType); } } }