using System; using System.Collections.Generic; using System.Linq; using ICD.Common.Properties; using ICD.Common.Utils.Extensions; namespace ICD.Common.Utils.Services { public sealed class ServiceProvider { private static ServiceProvider s_Instance; private readonly Dictionary m_Services; private readonly SafeCriticalSection m_ServicesSection; private static ServiceProvider Instance { get { return s_Instance ?? (s_Instance = new ServiceProvider()); } } /// /// Prevent external instantiation. /// private ServiceProvider() { m_Services = new Dictionary(); m_ServicesSection = new SafeCriticalSection(); } #region Methods /// /// Retrieves the registered service of the given type. Use this for required dependencies. /// /// service type to retrieve /// /// Thrown if a service of the given type is not registered [PublicAPI] [NotNull] public static TService GetService() { return (TService)GetService(typeof(TService)); } /// /// Retrieves the registered service of the given type. Use this for required dependencies. /// /// service type to retrieve /// /// Thrown if a service of the given type is not registered [PublicAPI] [NotNull] public static object GetService(Type tService) { if (tService == null) throw new ArgumentNullException("tService"); return Instance.GetServiceInstance(tService); } /// /// Retrieves the registered services. /// /// public static IEnumerable GetServices() { return Instance.GetServicesInstance(); } /// /// Retrieves the registered service of the given type. Returns null if the service type was not found. /// Use this for optional dependencies. /// /// service type to retrieve /// requested service or null if that service type is not registered [PublicAPI] [CanBeNull] public static TService TryGetService() { return (TService)TryGetService(typeof(TService)); } /// /// Retrieves the registered service of the given type. Returns null if the service type was not found. /// Use this for optional dependencies. /// /// service type to retrieve /// requested service or null if that service type is not registered [PublicAPI] [CanBeNull] public static object TryGetService(Type tService) { if (tService == null) throw new ArgumentNullException("tService"); return Instance.TryGetServiceInstance(tService); } /// /// Registers a service instance to the type given. /// /// /// [PublicAPI] public static void AddService(TService service) { // ReSharper disable once CompareNonConstrainedGenericWithNull if (service == null) throw new ArgumentNullException("service"); AddService(typeof(TService), service); } /// /// Registers a service instance to the type given. /// /// /// [PublicAPI] public static bool TryAddService(TService service) { // ReSharper disable once CompareNonConstrainedGenericWithNull if (service == null) throw new ArgumentNullException("service"); return TryAddService(typeof(TService), service); } /// /// Registers a service instance to the type given. /// /// /// [PublicAPI] public static void AddService(Type tService, object service) { if (tService == null) throw new ArgumentNullException("tService"); if (service == null) throw new ArgumentNullException("service"); Instance.AddServiceInstance(tService, service); } /// /// Registers a service instance to the type given. /// /// /// [PublicAPI] public static bool TryAddService(Type tService, object service) { if (tService == null) throw new ArgumentNullException("tService"); if (service == null) throw new ArgumentNullException("service"); return Instance.TryAddServiceInstance(tService, service); } /// /// Removes all of the registered services. /// [PublicAPI] public static void RemoveAllServices() { Instance.RemoveAllServicesInstance(); } /// /// Attempts to remove the given service from every registered type. /// /// [PublicAPI] public static void RemoveAllServices(object service) { // ReSharper disable once CompareNonConstrainedGenericWithNull if (service == null) throw new ArgumentNullException("service"); Instance.RemoveAllServicesInstance(service); } /// /// Attempts to remove the given service from the given type. /// /// /// /// [PublicAPI] public static bool RemoveService(TService service) { // ReSharper disable once CompareNonConstrainedGenericWithNull if (service == null) throw new ArgumentNullException("service"); return RemoveService(typeof(TService), service); } /// /// Attempts to remove the given service from the given type. /// /// /// /// [PublicAPI] public static bool RemoveService(Type tService, object service) { // ReSharper disable once CompareNonConstrainedGenericWithNull if (service == null) throw new ArgumentNullException("service"); return Instance.RemoveServiceInstance(tService, service); } #endregion #region Private Methods /// /// Retrieves the registered service of the given type. Returns null if the service type was not found. /// Use this for optional dependencies. /// /// service type to retrieve /// requested service or null if that service type is not registered [CanBeNull] private object TryGetServiceInstance(Type tService) { if (tService == null) throw new ArgumentNullException("tService"); try { m_ServicesSection.Enter(); object service; m_Services.TryGetValue(tService, out service); return service; } finally { m_ServicesSection.Leave(); } } /// /// Gets the service of the given type. /// /// /// private object GetServiceInstance(Type tService) { if (tService == null) throw new ArgumentNullException("tService"); object service = TryGetService(tService); if (service != null) return service; throw new ServiceNotFoundException(tService); } /// /// Gets the registered services. /// /// private IEnumerable GetServicesInstance() { return m_ServicesSection.Execute(() => m_Services.Values.ToList()); } /// /// Adds the given service under the given type. /// /// /// private void AddServiceInstance(Type tService, object service) { if (tService == null) throw new ArgumentNullException("tService"); if (service == null) throw new ArgumentNullException("service"); try { m_ServicesSection.Enter(); if (m_Services.ContainsKey(tService)) { string message = string.Format("{0} already contains a {1} service", GetType().Name, tService.Name); throw new InvalidOperationException(message); } m_Services.Add(tService, service); } finally { m_ServicesSection.Leave(); } } /// /// Adds the given service under the given type. /// /// /// private bool TryAddServiceInstance(Type tService, object service) { if (tService == null) throw new ArgumentNullException("tService"); if (service == null) throw new ArgumentNullException("service"); try { m_ServicesSection.Enter(); if (m_Services.ContainsKey(tService)) return false; m_Services.Add(tService, service); } finally { m_ServicesSection.Leave(); } return true; } /// /// Removes the given service from the given type. /// /// /// private bool RemoveServiceInstance(Type tService, object service) { if (tService == null) throw new ArgumentNullException("tService"); if (service == null) throw new ArgumentNullException("service"); try { m_ServicesSection.Enter(); if (!m_Services.ContainsKey(tService)) return false; return m_Services[tService] == service && m_Services.Remove(tService); } finally { m_ServicesSection.Leave(); } } /// /// Removes all of the registered services. /// private void RemoveAllServicesInstance() { m_ServicesSection.Execute(() => m_Services.Clear()); } /// /// Removes the given service from all registered types. /// /// private void RemoveAllServicesInstance(object service) { if (service == null) throw new ArgumentNullException("service"); m_ServicesSection.Execute(() => m_Services.RemoveAllValues(service)); } #endregion } }