using Serilog; using Splat; using System.Collections.Generic; using System.Linq; namespace SPTInstaller.Helpers; /// <summary> /// A helper class to handle simple service registration to Splat with constructor parameter injection /// </summary> /// <remarks>Splat only recognizes the registered types and doesn't account for interfaces :(</remarks> internal static class ServiceHelper { private static bool TryRegisterInstance<T, T2>(object[] parameters = null) { var instance = Activator.CreateInstance(typeof(T2), parameters); if (instance != null) { Locator.CurrentMutable.RegisterConstant<T>((T)instance); return true; } return false; } /// <summary> /// Register a class as a service /// </summary> /// <typeparam name="T">class to register</typeparam> public static void Register<T>() where T : class => Register<T, T>(); /// <summary> /// Register a class as a service by another type /// </summary> /// <typeparam name="T">type to register as</typeparam> /// <typeparam name="T2">class to register</typeparam> public static void Register<T, T2>() where T : class { var constructors = typeof(T2).GetConstructors(); foreach (var constructor in constructors) { var parmesan = constructor.GetParameters(); if (parmesan.Length == 0) { if (TryRegisterInstance<T, T2>()) return; continue; } List<object> parameters = new List<object>(); for (int i = 0; i < parmesan.Length; i++) { var parm = parmesan[i]; var parmValue = Get(parm.ParameterType); if (parmValue != null) parameters.Add(parmValue); } if (TryRegisterInstance<T, T2>(parameters.ToArray())) return; } } /// <summary> /// Get a service from splat /// </summary> /// <param name="type"></param> /// <returns></returns> /// <exception cref="InvalidOperationException">Thrown if the service isn't found</exception> public static object Get(Type type) { var service = Locator.Current.GetService(type); if (service == null) { var message = $"Could not locate service of type '{type.Name}'"; Log.Error(message); throw new InvalidOperationException(message); } return service; } /// <summary> /// Get a service from splat /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> /// <exception cref="InvalidOperationException">Thrown if the service isn't found</exception> public static T Get<T>() { var service = Locator.Current.GetService<T>(); if (service == null) { var message = $"Could not locate service of type '{nameof(T)}'"; Log.Error(message); throw new InvalidOperationException(message); } return service; } /// <summary> /// Get all services of a type /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> /// <exception cref="InvalidOperationException">thrown if no services are found</exception> public static T[] GetAll<T>() { var services = Locator.Current.GetServices<T>().ToArray(); if (services == null || services.Count() == 0) { var message = $"Could not locate service of type '{nameof(T)}'"; Log.Error(message); throw new InvalidOperationException(message); } return services; } }