diff --git a/Toolkit.Foundation/IServiceCollectionExtensions.cs b/Toolkit.Foundation/IServiceCollectionExtensions.cs index 44e11e1..47e50aa 100644 --- a/Toolkit.Foundation/IServiceCollectionExtensions.cs +++ b/Toolkit.Foundation/IServiceCollectionExtensions.cs @@ -41,43 +41,43 @@ public static class IServiceCollectionExtensions string? key = null) where THandler : IHandler { - if (typeof(THandler).GetInterfaces() is Type[] contracts) + if (typeof(THandler).GetInterfaces() is Type[] handlerTypes) { - foreach (Type contract in contracts) + foreach (Type handlerType in handlerTypes) { - if (contract.Name == typeof(INotificationHandler<>).Name && - contract.GetGenericArguments() is { Length: 1 } notificationHandlerArguments) + if (handlerType.Name == typeof(INotificationHandler<>).Name && + handlerType.GetGenericArguments() is { Length: 1 } notificationHandlerArguments) { Type notificationType = notificationHandlerArguments[0]; Type wrapperType = typeof(NotificationHandlerWrapper<>).MakeGenericType(notificationType); - string actualKey = $"{(key is not null ? $"{key}:" : "")}{notificationType}"; + string preferredKey = $"{(key is not null ? $"{key}:" : "")}{notificationType}"; services.Add(new ServiceDescriptor(typeof(INotificationHandler<>) - .MakeGenericType(notificationType), actualKey, typeof(THandler), lifetime)); + .MakeGenericType(notificationType), preferredKey, typeof(THandler), lifetime)); - services.Add(new ServiceDescriptor(wrapperType, actualKey, (provider, registeredKey) => + services.Add(new ServiceDescriptor(wrapperType, preferredKey, (provider, registeredKey) => provider.GetService()?.Create(wrapperType, provider.GetRequiredKeyedService(typeof(INotificationHandler<>).MakeGenericType(notificationType), registeredKey), provider.GetServices(typeof(IPipelineBehaviour<>) .MakeGenericType(notificationType)))!, lifetime)); } - if (contract.Name == typeof(IHandler<,>).Name && - contract.GetGenericArguments() is { Length: 2 } handlerArguments) + if (handlerType.Name == typeof(IHandler<,>).Name && + handlerType.GetGenericArguments() is { Length: 2 } handlerArguments) { Type requestType = handlerArguments[0]; Type responseType = handlerArguments[1]; Type wrapperType = typeof(HandlerWrapper<,>).MakeGenericType(requestType, responseType); - string actualKey = $"{(key is not null ? $"{key}:" : "")}{wrapperType}"; + string preferredKey = $"{(key is not null ? $"{key}:" : "")}{wrapperType}"; - services.Add(new ServiceDescriptor(typeof(THandler), actualKey, + services.Add(new ServiceDescriptor(typeof(THandler), preferredKey, typeof(THandler), lifetime)); - services.Add(new ServiceDescriptor(wrapperType, actualKey, (provider, actualKey) => + services.Add(new ServiceDescriptor(wrapperType, preferredKey, (provider, actualKey) => provider.GetService()?.Create(wrapperType, - provider.GetRequiredKeyedService(actualKey), + provider.GetRequiredKeyedService(preferredKey), provider.GetServices(typeof(IPipelineBehaviour<,>) .MakeGenericType(requestType, responseType)))!, lifetime)); } diff --git a/Toolkit.Foundation/Subscriber.cs b/Toolkit.Foundation/Subscriber.cs index 0e6d04d..593060e 100644 --- a/Toolkit.Foundation/Subscriber.cs +++ b/Toolkit.Foundation/Subscriber.cs @@ -8,107 +8,89 @@ public class Subscriber(SubscriptionCollection subscriptions, { public void Subscribe(object subscriber) { - Type handlerType = subscriber.GetType(); - IDictionary> subscribers = GetSubscriptionKeys(subscriber); - foreach (Type interfaceType in GetHandlerInterfaces(handlerType)) + + foreach (Type handlerType in GetHandlerInterfaces(subscriber.GetType())) { - if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType) + if (handlerType.Name == typeof(INotificationHandler<>).Name && + handlerType.GetGenericArguments() is { Length: 1 } notificationHandlerArguments) { - subscribers.TryGetValue(argumentType, out List? keys); - if (keys is not null) - { - foreach (object key in keys) - { - string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{argumentType}"; - subscriptions.AddOrUpdate(subscriptionKey, _ => new List { new(subscriber) }, (_, collection) => - { - collection.Add(new WeakReference(subscriber)); - return collection; - }); + Type notificationType = notificationHandlerArguments[0]; + AddSubscriptions(subscriber, subscribers, notificationType); + } - disposer.Add(subscriber, Disposable.Create(() => RemoveSubscriber(subscriber, subscriptionKey))); - } - } - else - { - string subscriptionKey = $"{argumentType}"; - subscriptions.AddOrUpdate(subscriptionKey, _ => new List { new(subscriber) }, (_, collection) => - { - collection.Add(new WeakReference(subscriber)); - return collection; - }); - - disposer.Add(subscriber, Disposable.Create(() => RemoveSubscriber(subscriber, subscriptionKey))); - } + if (handlerType.Name == typeof(IHandler<,>).Name && + handlerType.GetGenericArguments() is { Length: 2 } handlerArguments) + { + Type requestType = handlerArguments[0]; + Type responseType = handlerArguments[1]; + Type wrapperType = typeof(HandlerWrapper<,>).MakeGenericType(requestType, responseType); + AddSubscriptions(subscriber, subscribers, wrapperType); } } } public void Unsubscribe(object subscriber) { - Type handlerType = subscriber.GetType(); IDictionary> subscribers = GetSubscriptionKeys(subscriber); - foreach (Type interfaceType in GetHandlerInterfaces(handlerType)) + + foreach (Type handlerType in GetHandlerInterfaces(subscriber.GetType())) { - if (interfaceType.GetGenericArguments().FirstOrDefault() is Type argumentType) + if (handlerType.Name == typeof(INotificationHandler<>).Name && + handlerType.GetGenericArguments() is { Length: 1 } notificationHandlerArguments) { - subscribers.TryGetValue(argumentType, out List? keys); - if (keys is not null) - { - foreach (object key in keys) - { - string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{argumentType}"; - if (subscriptions.TryGetValue(subscriptionKey, out List? existing)) - { - for (int i = existing.Count - 1; i >= 0; i--) - { - if (!existing[i].IsAlive || existing[i].Target == subscriber) - { - existing.RemoveAt(i); - } - } - } - } - } - else - { - string subscriptionKey = $"{argumentType}"; - if (subscriptions.TryGetValue(subscriptionKey, out List? existing)) - { - for (int i = existing.Count - 1; i >= 0; i--) - { - if (!existing[i].IsAlive || existing[i].Target == subscriber) - { - existing.RemoveAt(i); - } - } - } - } + Type notificationType = notificationHandlerArguments[0]; + RemoveSubscriptions(subscriber, subscribers, notificationType); + } + + if (handlerType.Name == typeof(IHandler<,>).Name && + handlerType.GetGenericArguments() is { Length: 2 } handlerArguments) + { + Type requestType = handlerArguments[0]; + Type responseType = handlerArguments[1]; + Type wrapperType = typeof(HandlerWrapper<,>).MakeGenericType(requestType, responseType); + RemoveSubscriptions(subscriber, subscribers, wrapperType); } } } - private void RemoveSubscriber(object subscriber, - string key) + private void AddOrUpdateSubscription(object subscriber, string preferredKey) { - if (subscriptions.TryGetValue(key, out List? subscribers)) + subscriptions.AddOrUpdate(preferredKey, _ => new List { new(subscriber) }, (_, collection) => { - for (int i = subscribers.Count - 1; i >= 0; i--) - { - if (subscribers[i].Target == subscriber) - { - subscribers.RemoveAt(i); - } - } + collection.Add(new WeakReference(subscriber)); + return collection; + }); - if (subscribers.Count == 0) + disposer.Add(subscriber, Disposable.Create(() => RemoveSubscription(subscriber, preferredKey))); + } + + private void AddSubscriptions(object subscriber, IDictionary> subscribers, Type handlerType) + { + if (subscribers.TryGetValue(handlerType, out List? keys)) + { + foreach (object key in keys) { - subscriptions.TryRemove(key, out _); + string preferredKey = $"{(key is not null ? $"{key}:" : "")}{handlerType}"; + AddOrUpdateSubscription(subscriber, preferredKey); } } + else + { + string preferredKey = $"{handlerType}"; + AddOrUpdateSubscription(subscriber, preferredKey); + } } + private IEnumerable GetHandlerInterfaces(Type handlerType) => + handlerType.GetInterfaces().Where(interfaceType => + { + Type? definition = interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : null; + return definition == typeof(INotificationHandler<>) || + definition == typeof(IHandler<>) || + definition == typeof(IHandler<,>); + }); + private IDictionary> GetSubscriptionKeys(object subscriber) { Dictionary> keys = []; @@ -133,12 +115,40 @@ public class Subscriber(SubscriptionCollection subscriptions, return keys; } - private IEnumerable GetHandlerInterfaces(Type handlerType) => - handlerType.GetInterfaces().Where(interfaceType => + private void RemoveSubscription(object subscriber, + string key) + { + if (subscriptions.TryGetValue(key, out List? subscribers)) { - Type? definition = interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : null; - return definition == typeof(INotificationHandler<>) || - definition == typeof(IHandler<>) || - definition == typeof(IHandler<,>); - }); + for (int i = subscribers.Count - 1; i >= 0; i--) + { + if (subscribers[i].Target == subscriber) + { + subscribers.RemoveAt(i); + } + } + + if (subscribers.Count == 0) + { + subscriptions.TryRemove(key, out _); + } + } + } + + private void RemoveSubscriptions(object subscriber, IDictionary> subscribers, Type handlerType) + { + if (subscribers.TryGetValue(handlerType, out List? keys)) + { + foreach (object key in keys) + { + string subscriptionKey = $"{(key is not null ? $"{key}:" : "")}{handlerType}"; + RemoveSubscription(subscriber, subscriptionKey); + } + } + else + { + string subscriptionKey = $"{handlerType}"; + RemoveSubscription(subscriber, subscriptionKey); + } + } } \ No newline at end of file