我正在使用的这个容器有问题。当我向它实现注册服务时,它工作正常。但是当我只注册一个实现时,它会进入堆栈溢出异常
因为它在初始中一遍又一遍地调用 GetIntance 方法 检查已注册的类型。
我该如何解决这个问题?
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);
}
}
注册类型时,将Func
委托添加到_registeredTypes
字典中:
_registeredTypes.Add(typeof(I), () => GetInstance(typeof(C)));
因此,如果您采用Func<Test> testFactory = _registeredTypes[typeof(Test)];
,然后调用它(testFactory();
),它将调用GetInstance
以实际获取实例。
现在让我们看一下查找此对象的GetInstance
部分:
if (_registeredTypes.ContainsKey(type))
{
return _registeredTypes[type]();
}
因此,您的代码使用键type
从_registeredTypes
获取工厂,然后调用工厂方法返回实例。工厂方法调用同一类型的GetInstance
,后者使用键type
从_registeredTypes
获取工厂,然后调用工厂方法返回实例。工厂方法调用同一类型的GetInstance
,该方法使用键type
从_registeredTypes
获取工厂,然后调用...等。
如您所见,您将永远在字典中查找类型的工厂,调用工厂方法,而工厂方法又调用相同的GetInstance
方法,直到堆栈已满并且应用程序崩溃。
要解决此问题,您可以将GetInstance
分为两种方法:一种用于创建实例,另一种用于通过_registeredTypes
字典解析实例:
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);
}
然后,您可以将Register
方法更改为使用CreateInstance
:
public void Register<I, C>()
{
_registeredTypes.Add(typeof(I), () => CreateInstance(typeof(C)));
}
另外,一些建议:考虑类型A需要类型B需要类型A的情况。这也将导致 StackOverflowException。作为改进,您可能希望在导致崩溃之前检测到此问题,并引发自己的异常。