159 lines
4.3 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|