无限递归试图解析自定义 DI 容器中的类型
Infinite recursion trying to resolve type in custom DI container
我使用的这个容器有问题。当我使用它的实现注册服务时它工作正常。但是当我只注册一个实现时,它会转到 Whosebug 异常
cause it calls over and over the GetIntance method in the initial
check for an registered type.
我该如何解决这个问题?
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
获取工厂,然后调用工厂方法 return 实例。工厂方法调用GetInstance
相同的类型,使用键type
从_registeredTypes
获取工厂,然后调用工厂方法return实例。工厂方法为同一类型调用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)));
}
此外,一些建议:考虑 TypeA 需要 TypeB 需要 TypeA 的场景。这也将导致 WhosebugException。作为一项改进,您可能希望在它导致崩溃之前检测到它,并抛出您自己的异常。
我使用的这个容器有问题。当我使用它的实现注册服务时它工作正常。但是当我只注册一个实现时,它会转到 Whosebug 异常
cause it calls over and over the GetIntance method in the initial check for an registered type.
我该如何解决这个问题?
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
获取工厂,然后调用工厂方法 return 实例。工厂方法调用GetInstance
相同的类型,使用键type
从_registeredTypes
获取工厂,然后调用工厂方法return实例。工厂方法为同一类型调用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)));
}
此外,一些建议:考虑 TypeA 需要 TypeB 需要 TypeA 的场景。这也将导致 WhosebugException。作为一项改进,您可能希望在它导致崩溃之前检测到它,并抛出您自己的异常。