diff --git a/Source/Euonia.Modularity/Dependency/ILazyServiceProvider.cs b/Source/Euonia.Modularity/Dependency/ILazyServiceProvider.cs index 6d24b3a..8ec6a0e 100644 --- a/Source/Euonia.Modularity/Dependency/ILazyServiceProvider.cs +++ b/Source/Euonia.Modularity/Dependency/ILazyServiceProvider.cs @@ -5,63 +5,131 @@ /// public interface ILazyServiceProvider { - /// - /// - /// - /// - /// - T GetRequiredService(); - - /// - /// - /// - /// - /// - object GetRequiredService(Type serviceType); - - /// - /// - /// - /// - /// - T GetService(); - - /// - /// - /// - /// - /// - object GetService(Type serviceType); - - /// - /// - /// - /// - /// - /// - T GetService(T defaultValue); - - /// - /// - /// - /// - /// - /// - object GetService(Type serviceType, object defaultValue); - - /// - /// - /// - /// - /// - /// - object GetService(Type serviceType, Func factory); - - /// - /// - /// - /// - /// - /// - T GetService(Func factory); + /// + /// Get service of type from the . + /// + /// The type of service object to get. + /// + T GetRequiredService(); + + /// + /// Get service of type from the . + /// + /// + /// + object GetRequiredService(Type serviceType); + + /// + /// Get service of type from the . + /// + /// The type of service object to get. + /// + T GetService(); + + /// + /// Get service of type from the . + /// + /// + /// + object GetService(Type serviceType); + + /// + /// Get service of type from the . + /// + /// + /// The type of service object to get. + /// + T GetService(T defaultValue); + + /// + /// + /// + /// + /// + /// + object GetService(Type serviceType, object defaultValue); + + /// + /// Get service of from the . + /// + /// + /// + /// + object GetService(Type serviceType, Func factory); + + /// + /// Get service of type from the . + /// + /// + /// The type of service object to get. + /// + T GetService(Func factory); + + /// + /// Get service of from the . + /// + /// An object that specifies the type of service object to get. + /// An object that specifies the key of service object to get. + /// + object GetKeyedService(Type serviceType, object serviceKey); + + /// + /// Get service of type from the . + /// + /// The type of service object to get. + /// An object that specifies the key of service object to get. + /// + T GetRequiredKeyedService(object serviceKey); + + /// + /// Get service of type from the . + /// + /// The type of service object to get. + /// An object that specifies the key of service object to get. + /// + T GetKeyedService(object serviceKey); + + /// + /// Get service of type from the . + /// + /// + /// An object that specifies the key of service object to get. + /// + object GetRequiredKeyedService(Type serviceType, object serviceKey); + + /// + /// Get service of type from the . + /// + /// The type of service object to get. + /// An object that specifies the key of service object to get. + /// + /// + T GetKeyedService(object serviceKey, T defaultValue); + + /// + /// Get service of type from the . + /// + /// The type of service object to get. + /// An object that specifies the key of service object to get. + /// + /// + T GetKeyedService(object serviceKey, Func factory); + + /// + /// Get service of type from the . + /// + /// + /// An object that specifies the key of service object to get. + /// + /// + object GetKeyedService(Type serviceType, object serviceKey, Func factory); + + /// + /// Get service of type from the . + /// + /// + /// An object that specifies the key of service object to get. + /// + /// + object GetKeyedService(Type serviceType, object serviceKey, object defaultValue); } \ No newline at end of file diff --git a/Source/Euonia.Modularity/Dependency/LazyServiceProvider.Keyed.cs b/Source/Euonia.Modularity/Dependency/LazyServiceProvider.Keyed.cs new file mode 100644 index 0000000..d1f7ee4 --- /dev/null +++ b/Source/Euonia.Modularity/Dependency/LazyServiceProvider.Keyed.cs @@ -0,0 +1,55 @@ +using Microsoft.Extensions.DependencyInjection; +using Nerosoft.Euonia.Modularity; + +namespace System; + +public partial class LazyServiceProvider +{ + /// + public virtual T GetKeyedService(object serviceKey) + { + return (T)GetKeyedService(typeof(T), serviceKey); + } + + /// + public virtual object GetKeyedService(Type serviceType, object serviceKey) + { + return CachedServices.GetOrAdd(new ServiceIdentifier(serviceKey, serviceType), _ => new Lazy(() => ServiceProvider.GetKeyedService(serviceType, serviceKey))).Value; + } + + /// + public virtual T GetRequiredKeyedService(object serviceKey) + { + return (T)GetRequiredKeyedService(typeof(T), serviceKey); + } + + /// + public virtual object GetRequiredKeyedService(Type serviceType, object serviceKey) + { + return CachedServices.GetOrAdd(new ServiceIdentifier(serviceKey, serviceType), _ => new Lazy(() => ServiceProvider.GetRequiredKeyedService(serviceType, serviceKey))).Value!; + } + + /// + public virtual T GetKeyedService(object serviceKey, T defaultValue) + { + return (T)GetKeyedService(typeof(T), serviceKey, defaultValue); + } + + /// + public virtual T GetKeyedService(object serviceKey, Func factory) + { + return (T)GetKeyedService(typeof(T), serviceKey, provider => factory(provider)); + } + + /// + public virtual object GetKeyedService(Type serviceType, object serviceKey, Func factory) + { + return CachedServices.GetOrAdd(new ServiceIdentifier(serviceKey, serviceType), _ => new Lazy(() => factory(ServiceProvider))).Value; + } + + /// + public virtual object GetKeyedService(Type serviceType, object serviceKey, object defaultValue) + { + return CachedServices.GetOrAdd(new ServiceIdentifier(serviceKey, serviceType), _ => new Lazy(() => defaultValue)).Value; + } +} diff --git a/Source/Euonia.Modularity/Dependency/LazyServiceProvider.cs b/Source/Euonia.Modularity/Dependency/LazyServiceProvider.cs index 4db8eb7..4252300 100644 --- a/Source/Euonia.Modularity/Dependency/LazyServiceProvider.cs +++ b/Source/Euonia.Modularity/Dependency/LazyServiceProvider.cs @@ -1,100 +1,102 @@ -namespace System; +using System.Collections.Concurrent; +using Nerosoft.Euonia.Modularity; + +namespace System; /// /// Implementation of . /// -public class LazyServiceProvider : ILazyServiceProvider +public partial class LazyServiceProvider : ILazyServiceProvider { - /// - /// - /// - protected IDictionary CachedServices { get; set; } + /// + /// Gets the cached services. + /// + private ConcurrentDictionary> CachedServices { get; } = new(); - /// - /// - /// - protected IServiceProvider ServiceProvider { get; } + /// + /// Gets the service provider instance. + /// + private IServiceProvider ServiceProvider { get; } - /// - /// - /// - /// - public LazyServiceProvider(IServiceProvider serviceProvider) - { - ServiceProvider = serviceProvider; - CachedServices = new Dictionary(); - } + /// + /// Initializes a new instance of the class. + /// + /// + public LazyServiceProvider(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } - /// - public virtual T GetRequiredService() - { - return (T)GetRequiredService(typeof(T)); - } + /// + public virtual T GetRequiredService() + { + return (T)GetRequiredService(typeof(T)); + } - /// - /// - /// - /// - /// - /// - /// - public virtual object GetRequiredService(Type serviceType) - { - return CachedServices.GetOrAdd(serviceType, () => - { - if (ServiceProvider == null) - { - throw new ArgumentNullException(nameof(ServiceProvider)); - } + /// + /// + /// + /// + /// + /// + /// + public virtual object GetRequiredService(Type serviceType) + { + return CachedServices.GetOrAdd(new ServiceIdentifier(serviceType), _ => new Lazy(() => + { + if (ServiceProvider == null) + { + throw new ArgumentNullException(nameof(ServiceProvider)); + } - if (serviceType == null) - { - throw new ArgumentNullException(nameof(serviceType)); - } + if (serviceType == null) + { + throw new ArgumentNullException(nameof(serviceType)); + } - var service = ServiceProvider.GetService(serviceType); - if (service == null) - { - throw new NullReferenceException(nameof(serviceType)); - } + var service = ServiceProvider.GetService(serviceType); + if (service == null) + { + throw new NullReferenceException(nameof(serviceType)); + } - return service; - }); - } + return service; + })).Value; + } - /// - public virtual T GetService() - { - return (T)GetService(typeof(T)); - } + /// + public virtual T GetService() + { + return (T)GetService(typeof(T)); + } - /// - public virtual object GetService(Type serviceType) - { - return CachedServices.GetOrAdd(serviceType, () => ServiceProvider.GetService(serviceType)); - } + /// + public virtual object GetService(Type serviceType) + { + return CachedServices.GetOrAdd(new ServiceIdentifier(serviceType), _ => new Lazy(() => ServiceProvider.GetService(serviceType))).Value; + } - /// - public virtual T GetService(T defaultValue) - { - return (T)GetService(typeof(T), defaultValue); - } + /// + public virtual T GetService(T defaultValue) + { + return (T)GetService(typeof(T), defaultValue); + } - /// - public virtual object GetService(Type serviceType, object defaultValue) - { - return GetService(serviceType) ?? defaultValue; - } + /// + public virtual object GetService(Type serviceType, object defaultValue) + { + return GetService(serviceType) ?? defaultValue; + } - /// - public virtual T GetService(Func factory) - { - return (T)GetService(typeof(T), factory); - } + /// + public virtual T GetService(Func factory) + { + return (T)GetService(typeof(T), factory); + } - /// - public virtual object GetService(Type serviceType, Func factory) - { - return CachedServices.GetOrAdd(serviceType, () => factory(ServiceProvider)); - } + /// + public virtual object GetService(Type serviceType, Func factory) + { + return CachedServices.GetOrAdd(new ServiceIdentifier(serviceType), _ => new Lazy(() => factory(ServiceProvider))).Value; + } } \ No newline at end of file diff --git a/Source/Euonia.Modularity/Dependency/ServiceIdentifier.cs b/Source/Euonia.Modularity/Dependency/ServiceIdentifier.cs new file mode 100644 index 0000000..bcb47b9 --- /dev/null +++ b/Source/Euonia.Modularity/Dependency/ServiceIdentifier.cs @@ -0,0 +1,49 @@ +namespace Nerosoft.Euonia.Modularity; + +internal readonly struct ServiceIdentifier : IEquatable +{ + public object ServiceKey { get; } + + public Type ServiceType { get; } + + public ServiceIdentifier(Type serviceType) + { + ServiceType = serviceType; + } + + public ServiceIdentifier(object serviceKey, Type serviceType) + { + ServiceKey = serviceKey; + ServiceType = serviceType; + } + + public bool Equals(ServiceIdentifier other) + { + if (ServiceKey == null && other.ServiceKey == null) + { + return ServiceType == other.ServiceType; + } + else if (ServiceKey != null && other.ServiceKey != null) + { + return ServiceType == other.ServiceType && ServiceKey.Equals(other.ServiceKey); + } + return false; + } + + public override bool Equals(object obj) + { + return obj is ServiceIdentifier && Equals((ServiceIdentifier)obj); + } + + public override int GetHashCode() + { + if (ServiceKey == null) + { + return ServiceType.GetHashCode(); + } + unchecked + { + return (ServiceType.GetHashCode() * 397) ^ ServiceKey.GetHashCode(); + } + } +} diff --git a/Source/Euonia.Modularity/Extensions/ServiceProviderExtensions.cs b/Source/Euonia.Modularity/Extensions/ServiceProviderExtensions.cs index 0533c88..aad1fed 100644 --- a/Source/Euonia.Modularity/Extensions/ServiceProviderExtensions.cs +++ b/Source/Euonia.Modularity/Extensions/ServiceProviderExtensions.cs @@ -1,4 +1,6 @@ -namespace System; +using Microsoft.Extensions.DependencyInjection; + +namespace System; /// /// The extension methods for interface. @@ -33,4 +35,22 @@ public static TService GetNamedRequiredService(this IServiceProvider p var @delegate = (NamedService)provider.GetService(typeof(NamedService)); return @delegate?.Invoke(name) ?? throw new InvalidOperationException($"The service {typeof(TService).FullName} with name {name} was not found."); } + + /// + /// Gets the service object of the specified type. + /// + /// + /// An object that specifies the type of service object to get. + /// An object that specifies the key of service object to get. + /// + /// + public static object GetKeyedService(this IServiceProvider provider, Type serviceType, object serviceKey) + { + if (provider is IKeyedServiceProvider keyedServiceProvider) + { + return keyedServiceProvider.GetKeyedService(serviceType, serviceKey); + } + + throw new InvalidOperationException("This service provider doesn't support keyed services."); + } }