namespace CommonConsole { using System; using System.Collections.Concurrent; using System.Linq; using System.Reflection; public partial class Program { class Outer { private readonly Middle middle; Outer(Middle middle) { Console.WriteLine($"{nameof(Outer)}: I am transient!"); this.middle = middle; } internal string Text => $"{nameof(Outer)}.{nameof(Text)} => {this.middle.Text}"; } class Middle { private readonly Inner inner; Middle(Inner inner) { Console.WriteLine($"{nameof(Middle)}: I am transient!"); this.inner = inner; } internal string Text => $"{nameof(Middle)}.{nameof(Text)} => {this.inner.Text}"; } class Inner { private readonly string text; internal Inner(string text) { Console.WriteLine($"{nameof(Inner)}: I am singleton!"); this.text = text; } internal string Text => $"{nameof(Inner)}.{nameof(Text)} => {this.text}"; } public static void DependencyInjectionTest() { ServiceProvider .ServiceCollection .AddSingleton(new Inner("It works!")); var outer = ServiceProvider.GetService(); Console.WriteLine(outer.Text); } } public interface IServiceCollection { IServiceCollection AddSingleton(T instance); } public class ServiceProvider : IServiceProvider, IServiceCollection { private static readonly ServiceProvider serviceProvider = new ServiceProvider(); private readonly ConcurrentDictionary services; private ServiceProvider() { this.services = new ConcurrentDictionary(); } public IServiceCollection AddSingleton(T instance) { services.AddOrUpdate(typeof(T), instance, (t, i) => instance); return this; } public object GetService(Type serviceType) { return services.GetOrAdd(serviceType, default(object)); } public static IServiceCollection ServiceCollection { get => serviceProvider; } public static T GetService() { var serviceType = typeof(T); var serviceInstance = default(T); if (serviceProvider.GetService(serviceType) is T existingInstance) { serviceInstance = existingInstance; } else if (CreateInstance(serviceType) is T newInstance) { serviceInstance = newInstance; } return serviceInstance; } private static object CreateInstance(Type instanceType) { var instance = default(object); var constructors = instanceType .GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .OrderByDescending(x => x.GetParameters().Length); foreach (var constructor in constructors) { var parameters = constructor.GetParameters(); var parametersLength = parameters.Length; var createParameters = new object[parametersLength]; for (int i = 0; i < parametersLength; i++) { var parameterType = parameters[i].ParameterType; var parameter = serviceProvider.GetService(parameterType); if (parameter is null) { parameter = CreateInstance(parameterType); } createParameters[i] = parameter; } try { instance = constructor.Invoke(createParameters); if (instance != null) { break; } } catch (Exception e) { Console.WriteLine(e); } } return instance; } } }