无限递归试图解析自定义 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。作为一项改进,您可能希望在它导致崩溃之前检测到它,并抛出您自己的异常。