laatzen/Common/CommonConsole/ServiceProvider.cs
Stoyan Zlatev 02943ebcbc omni before testing,
- recalculating correction factors and accuracies
- factory unseal
2024-02-05 14:48:35 +01:00

159 lines
4.3 KiB
C#

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<Outer>();
Console.WriteLine(outer.Text);
}
}
public interface IServiceCollection
{
IServiceCollection AddSingleton<T>(T instance);
}
public class ServiceProvider : IServiceProvider, IServiceCollection
{
private static readonly ServiceProvider serviceProvider = new ServiceProvider();
private readonly ConcurrentDictionary<Type, object> services;
private ServiceProvider()
{
this.services = new ConcurrentDictionary<Type, object>();
}
public IServiceCollection AddSingleton<T>(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<T>()
{
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;
}
}
}