尝试解析自定义 DI 容器中的类型的无限递归



我正在使用的这个容器有问题。当我向它实现注册服务时,它工作正常。但是当我只注册一个实现时,它会进入堆栈溢出异常

因为它在初始中一遍又一遍地调用 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。作为改进,您可能希望在导致崩溃之前检测到此问题,并引发自己的异常。

最新更新