-
Notifications
You must be signed in to change notification settings - Fork 7
/
Ioc.linq
151 lines (118 loc) · 3.95 KB
/
Ioc.linq
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<Query Kind="Program" />
/// <summary>
/// This is a thought experiment into the
/// insides of a simpler IoC Container
/// </summary>
void Main()
{
string input = "Input Data";
ContainerA.Register<ITest, Test>();
var test = ContainerA.Resolve<ITest>();
test.Method(input);
var containerB = new ContainerB();
containerB.Register<ITest>(() => new Test());
var instance = (Test)containerB.GetInstance<ITest>();
instance.Method(input);
var containerC = new ContainerC();
containerC.Register<ITest>(delegate { return new Test(); });
var result = containerC.Create<ITest>();
result.Method(input);
}
public interface ITest
{
void Method(string Input);
}
public class Test : ITest
{
public void Method(string Input) => Input.Dump("Test");
}
//Raw IoC: Definitely not for production use
public static class ContainerA
{
private static readonly Dictionary<Type, Type> types = new();
private static readonly Dictionary<Type, object> typeInstances = new();
public static void Register<TContract, TImplementation>()
{
types[typeof(TContract)] = typeof(TImplementation);
}
public static void Register<TContract, TImplementation>(TImplementation instance)
=> typeInstances[typeof(TContract)] = instance;
public static T Resolve<T>() => (T)Resolve(typeof(T));
public static object Resolve(Type contract)
{
if (typeInstances.ContainsKey(contract))
{
return typeInstances[contract];
}
Type implementation = types[contract];
ConstructorInfo constructor = implementation.GetConstructors()[0];
ParameterInfo[] constructorParameters = constructor.GetParameters();
if (constructorParameters.Length == 0)
{
return Activator.CreateInstance(implementation);
}
List<object> parameters = new(constructorParameters.Length);
foreach (ParameterInfo parameterInfo in constructorParameters)
{
parameters.Add(Resolve(parameterInfo.ParameterType));
}
return constructor.Invoke(parameters.ToArray());
}
}
// Taken from this SO post
// https://stackoverflow.com/questions/15715978/simple-dependency-resolver/15717047#15717047
public class ContainerB
{
private readonly Dictionary<Type, Func<object>> regs = new();
public void Register<TService, TImpl>() where TImpl : TService =>
regs.Add(typeof(TService), () => this.GetInstance(typeof(TImpl)));
public void Register<TService>(Func<TService> factory) =>
regs.Add(typeof(TService), () => factory());
public void RegisterInstance<TService>(TService instance) =>
regs.Add(typeof(TService), () => instance);
public void RegisterSingleton<TService>(Func<TService> factory)
{
var lazy = new Lazy<TService>(factory);
Register(() => lazy.Value);
}
public object GetInstance<T>() => this.GetInstance(typeof(T));
public object GetInstance(Type type)
{
if (regs.TryGetValue(type, out Func<object> fac)) return fac();
else if (!type.IsAbstract) return this.CreateInstance(type);
throw new InvalidOperationException("No registration for " + type);
}
private object CreateInstance(Type implementationType)
{
var ctor = implementationType.GetConstructors().Single();
var paramTypes = ctor.GetParameters().Select(p => p.ParameterType);
var dependencies = paramTypes.Select(GetInstance).ToArray();
return Activator.CreateInstance(implementationType, dependencies);
}
}
// Taken from this Ayende post
// https://ayende.com/blog/2886/building-an-ioc-container-in-15-lines-of-code
public class ContainerC
{
public delegate object Creator(ContainerC container);
private readonly Dictionary<string, object> configuration
= new Dictionary<string, object>();
private readonly Dictionary<Type, Creator> typeToCreator
= new Dictionary<Type, Creator>();
public Dictionary<string, object> Configuration
{
get { return configuration; }
}
public void Register<T>(Creator creator)
{
typeToCreator.Add(typeof(T), creator);
}
public T Create<T>()
{
return (T)typeToCreator[typeof(T)](this);
}
public T GetConfiguration<T>(string name)
{
return (T)configuration[name];
}
}