I have a issue with this container I'm using. It works fine when I register a service with it implementation. But when I'm registering just a implementation it goes to Stackoverflow Exception
cause it calls over and over the GetIntance method in the initial check for an registered type.
How I can solve this?
public class DIContainer
{
private readonly Dictionary<Type, Func<object>> _registeredTyped = new Dictionary<Type, Func<objec>>();
public void Register<I, C>()
{
_registeredTypes.Add(typeof(I), () => GetInstance(typeof(C)));
}
public void RegisterSinglenton<T>(T obj)
{
_registeredTypes.Add(typeof(T), () => obj);
}
public T Get<T>()
{
return (T)GetInstance(typeof(T));
}
public object GetInstance(Type type)
{
if (_registeredTypes.ContainsKey(type))
{
return _registeredTypes[type]();
}
var constructor = type.GetConstructors().OrderByDescending(c => c.GetParameters().Length).First();
var args = constructor.GetParameters().Select(p => GetInstance(p.ParameterType)).ToArray();
return Activator.CreateInstance(type, args);
}
}
When you register a type, you add a Func
delegate to your _registeredTypes
dictionary:
_registeredTypes.Add(typeof(I), () => GetInstance(typeof(C)));
So if you take Func<Test> testFactory = _registeredTypes[typeof(Test)];
, and then call it (testFactory();
), it will make a call to GetInstance
to actually obtain the instance.
Now let's take a look at the part of GetInstance
that looks this object up:
if (_registeredTypes.ContainsKey(type))
{
return _registeredTypes[type]();
}
So your code is obtaining the factory from _registeredTypes
using the key type
, and then it calls the factory method to return the instance. The factory method calls GetInstance
for the same type, which obtains the factory from _registeredTypes
using the key type
, and then it calls the factory method to return the instance. The factory method calls GetInstance
for the same type, which obtains the factory from _registeredTypes
using the key type
, and then it calls... etc.
As you can see, you'll forever go around in a loop of looking up the type's factory in the dictionary, calling the factory method, which in turn calls the very same GetInstance
method, until the stack is full and your application crashes.
To solve this you can separate the GetInstance
into two methods: one for creating instances, one for resolving instances through the _registeredTypes
dictionary:
public object GetInstance(Type type)
{
if (_registeredTypes.ContainsKey(type))
{
return _registeredTypes[type]();
}
else
{
return null; // or throw an exception, etc.
}
}
public object CreateInstance(Type type)
{
var constructor = type.GetConstructors().OrderByDescending(c => c.GetParameters().Length).First();
var args = constructor.GetParameters().Select(p => GetInstance(p.ParameterType)).ToArray();
return Activator.CreateInstance(type, args);
}
And then you can change your Register
method to use CreateInstance
:
public void Register<I, C>()
{
_registeredTypes.Add(typeof(I), () => CreateInstance(typeof(C)));
}
Also, some advice: consider the scenario where TypeA requires TypeB requires TypeA. This will also lead to a StackOverflowException. As an improvement, you might want to detect this before it leads to a crash, and throw your own exception.