Damn garbage collector

This commit is contained in:
TheXamlGuy
2024-01-15 22:02:30 +00:00
parent 2a494e1b94
commit f0ef3d1604
47 changed files with 452 additions and 257 deletions
@@ -13,7 +13,7 @@ public static class IServiceCollectionExtensions
where TKey :
notnull
{
services.AddSingleton<ICache<TKey, TValue>, Cache<TKey, TValue>>();
services.AddScoped<ICache<TKey, TValue>, Cache<TKey, TValue>>();
services.AddTransient(provider => provider.GetService<ICache<TKey, TValue>>()!.Select(x => x.Value));
return services;
+5 -3
View File
@@ -31,18 +31,20 @@ public class Cache<TValue>(IDisposer disposer) :
public class Cache<TKey, TValue>(IDisposer disposer) :
ICache<TKey, TValue>
where TKey : notnull
where TValue : notnull
{
private readonly ConcurrentDictionary<TKey, TValue> cache = new();
public void Add(TKey key,
TValue value)
{
disposer.Add(value!, Disposable.Create(() =>
cache.TryAdd(key, value);
disposer.Add(key, Disposable.Create(() =>
{
disposer.Dispose(value);
Remove(key);
}));
cache.TryAdd(key, value);
}
public void Clear() => cache.Clear();
+29 -8
View File
@@ -1,18 +1,39 @@
using System.Runtime.CompilerServices;
using System.Reactive.Disposables;
using System.Collections;
using System.Collections.Concurrent;
namespace Hyperbar;
public class AsyncLock(int initial = 1,
int maximum = 1) : IDisposable
{
private readonly SemaphoreSlim semaphore = new(initial, maximum);
public void Dispose()
{
semaphore.Release();
}
public TaskAwaiter<AsyncLock> GetAwaiter() => LockAsync().GetAwaiter();
private async Task<AsyncLock> LockAsync()
{
await semaphore.WaitAsync();
return this;
}
}
public class Disposer :
IDisposer
{
private readonly ConditionalWeakTable<object, CompositeDisposable> subjects = [];
private readonly ConcurrentDictionary<object, CompositeDisposable> subjects = [];
public void Add(object subject,
params object[] objects)
{
CompositeDisposable disposables = subjects.GetOrCreateValue(subject);
CompositeDisposable disposables = subjects.GetOrAdd(subject, args => new CompositeDisposable());
foreach (IDisposable disposable in objects.OfType<IDisposable>())
{
disposables.Add(disposable);
@@ -26,17 +47,17 @@ public class Disposer :
private void FromNotDisposable(object target)
{
if (target is IEnumerable enumerableTarget)
if (target is IList collection && collection is { Count: > 0 })
{
foreach (object? item in enumerableTarget)
foreach (object? item in collection)
{
FromNotDisposable(item);
}
}
if (target is IDisposable disposableTarget)
if (target is IDisposable disposable)
{
disposableTarget.Dispose();
disposable.Dispose();
}
if (target is not IDisposable)
@@ -51,7 +72,7 @@ public class Disposer :
where TDisposable :
IDisposable
{
CompositeDisposable disposables = subjects.GetOrCreateValue(subject);
CompositeDisposable disposables = subjects.GetOrAdd(subject, args => new CompositeDisposable());
if (disposer is not null)
{
disposables.Remove(disposer);
@@ -64,7 +85,7 @@ public class Disposer :
public void Remove(object subject,
IDisposable disposer)
{
CompositeDisposable disposables = subjects.GetOrCreateValue(subject);
CompositeDisposable disposables = subjects.GetOrAdd(subject, args => new CompositeDisposable());
if (disposer is not null)
{
disposables.Remove(disposer);
+3
View File
@@ -0,0 +1,3 @@
namespace Hyperbar;
public record Request<TValue> : INotification;
+6
View File
@@ -0,0 +1,6 @@
namespace Hyperbar;
public interface IDispatcher
{
Task InvokeAsync(Action action);
}
+5
View File
@@ -7,6 +7,11 @@ public interface IMediator
where TNotification :
INotification;
ValueTask PublishAsync<TNotification>(CancellationToken cancellationToken = default)
where TNotification :
INotification,
new();
ValueTask<TResponse> SendAsync<TResponse>(IRequest<TResponse> request,
CancellationToken cancellationToken = default);
+5 -6
View File
@@ -1,14 +1,8 @@
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
using System.Reactive.Concurrency;
namespace Hyperbar;
public interface IDispatcher
{
Task InvokeAsync(Action action);
}
public class Mediator(IServiceProvider provider,
IDispatcher dispatcher) :
IMediator
@@ -42,6 +36,11 @@ public class Mediator(IServiceProvider provider,
}
}
public ValueTask PublishAsync<TNotification>(CancellationToken cancellationToken = default)
where TNotification :
INotification,
new() => PublishAsync(new TNotification(), cancellationToken);
public ValueTask<TResponse> SendAsync<TResponse>(IRequest<TResponse> request,
CancellationToken cancellationToken = default)
{
@@ -7,5 +7,4 @@ public interface IObservableCollectionViewModel<TItem> :
IList<TItem>,
IList,
IReadOnlyList<TItem>,
INotifyCollectionChanged,
IInitializer;
INotifyCollectionChanged;
@@ -0,0 +1,10 @@
using System.Windows.Input;
namespace Hyperbar;
public interface IViewModelInitialization
{
ICommand Initialize { get; }
Task InitializeAsync();
}
+1 -1
View File
@@ -1,3 +1,3 @@
namespace Hyperbar;
public interface IWidgetComponentViewModel;
public interface IWidgetComponentViewModel : IDisposable;
+1 -1
View File
@@ -1,3 +1,3 @@
namespace Hyperbar;
public interface IWidgetViewModel;
public interface IWidgetViewModel : IDisposable;
+44 -49
View File
@@ -1,10 +1,8 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Reactive.Disposables;
using System.Windows.Input;
namespace Hyperbar;
@@ -12,22 +10,21 @@ public partial class ObservableCollectionViewModel<TItem> :
ObservableObject,
IObservableCollectionViewModel<TItem>,
INotificationHandler<Removed<TItem>>,
INotificationHandler<Created<TItem>>
INotificationHandler<Created<TItem>>,
IDisposable
where TItem :
IDisposable
{
public ObservableCollection<TItem> collection = [];
private readonly SynchronizationContext? context;
private readonly IDisposer disposer;
private readonly IViewModelEnumerator<TItem>? enumerator;
private readonly IServiceFactory serviceFactory;
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer)
{
context = SynchronizationContext.Current;
this.serviceFactory = serviceFactory;
this.disposer = disposer;
ServiceFactory = serviceFactory;
Mediator = mediator;
Disposer = disposer;
mediator.Subscribe(this);
@@ -39,16 +36,16 @@ public partial class ObservableCollectionViewModel<TItem> :
IDisposer disposer,
IViewModelEnumerator<TItem> enumerator)
{
context = SynchronizationContext.Current;
ServiceFactory = serviceFactory;
Mediator = mediator;
Disposer = disposer;
this.serviceFactory = serviceFactory;
this.disposer = disposer;
this.enumerator = enumerator;
mediator.Subscribe(this);
collection.CollectionChanged += OnCollectionChanged;
if (enumerator is not null)
{
foreach (TItem? item in enumerator.Next())
@@ -66,10 +63,9 @@ public partial class ObservableCollectionViewModel<TItem> :
IDisposer disposer,
IEnumerable<TItem> items)
{
context = SynchronizationContext.Current;
this.serviceFactory = serviceFactory;
this.disposer = disposer;
ServiceFactory = serviceFactory;
Mediator = mediator;
Disposer = disposer;
mediator.Subscribe(this);
@@ -82,10 +78,6 @@ public partial class ObservableCollectionViewModel<TItem> :
public int Count => collection.Count;
public ICommand Initialize => new AsyncRelayCommand(InitializeAsync);
public bool Initialized { get; private set; }
bool IList.IsFixedSize => false;
bool ICollection<TItem>.IsReadOnly => false;
@@ -96,8 +88,14 @@ public partial class ObservableCollectionViewModel<TItem> :
object ICollection.SyncRoot => this;
protected IDisposer Disposer { get; private set; }
protected IList<TItem> Items => collection;
protected IMediator Mediator { get; private set; }
protected IServiceFactory ServiceFactory { get; private set; }
public TItem this[int index]
{
get => collection[index];
@@ -129,7 +127,7 @@ public partial class ObservableCollectionViewModel<TItem> :
public TItem Add()
{
TItem? item = serviceFactory.Create<TItem>();
TItem? item = ServiceFactory.Create<TItem>();
Add(item);
return item;
@@ -138,7 +136,7 @@ public partial class ObservableCollectionViewModel<TItem> :
public TItem Add<T>(params object?[] parameters)
where T : TItem
{
T? item = serviceFactory.Create<T>(parameters);
T? item = ServiceFactory.Create<T>(parameters);
Add(item);
return item;
@@ -148,7 +146,7 @@ public partial class ObservableCollectionViewModel<TItem> :
where T :
TItem
{
T? item = serviceFactory.Create<T>();
T? item = ServiceFactory.Create<T>();
Add(item);
return item;
@@ -156,15 +154,6 @@ public partial class ObservableCollectionViewModel<TItem> :
public void Add(TItem item)
{
disposer.Add(this, item);
disposer.Add(item, Disposable.Create(item, args =>
{
if (Contains(args))
{
Remove(args);
}
}));
int index = collection.Count;
InsertItem(index, item);
}
@@ -208,7 +197,9 @@ public partial class ObservableCollectionViewModel<TItem> :
void ICollection.CopyTo(Array array, int index) =>
collection.CopyTo((TItem[])array, index);
public IEnumerator<TItem> GetEnumerator() =>
public void Dispose() => Disposer.Dispose(this);
public IEnumerator<TItem> GetEnumerator() =>
collection.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() =>
@@ -245,23 +236,13 @@ public partial class ObservableCollectionViewModel<TItem> :
return ValueTask.CompletedTask;
}
public int IndexOf(TItem item) => collection.IndexOf(item);
public int IndexOf(TItem item) =>
collection.IndexOf(item);
int IList.IndexOf(object? value) =>
IsCompatibleObject(value) ?
IndexOf((TItem)value!) : -1;
public Task InitializeAsync()
{
if (Initialized)
{
return Task.CompletedTask;
}
Initialized = true;
return Task.CompletedTask;
}
public void Insert(int index, TItem item) =>
InsertItem(index, item);
@@ -279,6 +260,7 @@ public partial class ObservableCollectionViewModel<TItem> :
int index = collection.IndexOf(item);
if (index < 0) return false;
Disposer.Remove(this, item);
RemoveItem(index);
return true;
@@ -299,7 +281,20 @@ public partial class ObservableCollectionViewModel<TItem> :
collection.Clear();
protected virtual void InsertItem(int index,
TItem value) => collection.Insert(index, value);
TItem value)
{
Disposer.Add(this, Disposable.Create(() =>
{
Remove(value);
}));
Disposer.Add(value, Disposable.Create(() =>
{
Remove(value);
}));
collection.Insert(index, value);
}
protected virtual void RemoveItem(int index) =>
collection.RemoveAt(index);
@@ -317,4 +312,4 @@ public partial class ObservableCollectionViewModel<TItem> :
public class ObservableCollectionViewModel(IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer) :
ObservableCollectionViewModel<object>(serviceFactory, mediator, disposer);
ObservableCollectionViewModel<IDisposable>(serviceFactory, mediator, disposer);
@@ -18,6 +18,7 @@ public partial class WidgetComponentViewModel :
Guid id = default) : base(serviceFactory, mediator, disposer, items)
{
this.id = id;
TemplateFactory = templateFactory;
}
@@ -28,6 +29,7 @@ public partial class WidgetComponentViewModel :
Guid id = default) : base(serviceFactory, mediator, disposer)
{
this.id = id;
TemplateFactory = templateFactory;
}