1

我是一名学生,我的工作是构建自己的 IoC 容器。我已经阅读了一些教程/代码示例并最终创建了它,但是当我尝试创建它的实例时,我得到了主题中的异常。这是我的 IoC 代码和测试代码,我一直在试图找出问题所在,但就是找不到。

国际奥委会

public class Mkontener: UnresolvedDependenciesException, IContainer
{
    private readonly Dictionary<Type, object> container = new Dictionary<Type, object> { };

    public void Register(System.Reflection.Assembly assembly)
    {

        Type[] mytypes = assembly.GetTypes();


        foreach (Type t in mytypes)
        {
            if (!container.ContainsKey(t))
            {
                container.Add(t, Activator.CreateInstance(t));
            }
        }
        //throw new NotImplementedException();
    }

    public void Register(Type type)
    {
        if (!container.ContainsKey(type))
        {
            container.Add(type, Activator.CreateInstance(type));
        }
        //throw new NotImplementedException();
    }

    public void Register(object impl)
    {
        Type t = impl.GetType();
        if (!container.ContainsKey(t))
        {
            container.Add(t, impl);
        }

        // throw new NotImplementedException();
    }

    public void Register<T>(Func<T> provider) where T : class
    {

        container.Add(provider.GetType(), provider);
        //throw new NotImplementedException();
    }

    public T Resolve<T>() where T : class
    {

        return (T)Resolve(typeof(T));
    }

    public object Resolve(Type type)
    {
        List<ConstructorInfo> konstruktor = new List<ConstructorInfo> { };
        foreach (ConstructorInfo cons in type.GetConstructors())
        {
            konstruktor.Add(cons);
        }
        if (konstruktor.Count == 0)
        {
            return Activator.CreateInstance(type);
        }
        else
        {
            ConstructorInfo active = null;
            int lparams = 0;
            foreach (ConstructorInfo cnst in konstruktor)
            {
                int inner=0;
                foreach (ParameterInfo a in cnst.GetParameters())
                {
                    inner++;
                }
                if (inner > lparams)
                {
                    active = cnst;
                }

            }
            List<object> lista = new List<object> { };
            foreach(ParameterInfo param in active.GetParameters())
            {
                if (container.ContainsKey(param.GetType()))
                {
                    lista.Add(container[param.GetType()]);
                }
                else
                {
                    //throw new UnresolvedDependenciesException();
                }
            }

            object[] obiekty= lista.ToArray();
            return  Activator.CreateInstance(type, obiekty);
        }
        if (container.ContainsKey(type))
        {
            return container[type];
        }
        else
        {
            //throw new UnresolvedDependenciesException();
        }

    }


    public void Register<T>(T impl) where T : class
    {
        container.Add(impl.GetType(), impl);
    }
}

部分测试单元

public void P1__Container_Should_Register_Singleton_As_Object()
{
    // Arrange
    var container = (IContainer)Activator.CreateInstance(LabDescriptor.Container);
    var singleton = new FakeImpl();

    // Act
    container.Register(singleton);
    var result = container.Resolve<IFake>();

    // Assert
    Assert.That(result, Is.Not.Null);
    Assert.That(result, Is.SameAs(singleton));
}

对不起,笨拙的代码等。刚从这里开始。

4

1 回答 1

0

如果您刚刚开始,尝试对 IOC 容器进行逆向工程并不是您真正应该尝试解决的问题。我重新实现了您提供的代码,填补了一些空白,但据我所知,您错过了容器的要点。

class Mkontener: UnresolvedDependenciesException, IContainer

如果 Mkontener 将成为您的容器类,为什么它将看起来像自定义异常的东西扩展为基类?此外,您正在尝试实现 IContainer 接口。如果这是 ComponentModel 的 IContainer,那么您的类将无法编译。如果您创建了自己的 IContainer 接口,那么我建议使用更合适的名称以避免混淆/命名冲突。

IOC 容器通过以下任一方式工作:A)针对接口注册具体类型。(并让容器在被要求提供接口时弄清楚如何设置具体类型的新实例,并管理范围。即单例与每个请求的实例) B)针对接口注册具体实例。(经典的单例行为)

您的实施既没有做。Register 需要接受一个具体类型和一个接口类型。Resolve 将被告知要使用哪个接口,然后构造(或返回)注册的具体类型的实例。像您尝试编写的一个简单示例只不过是一个动态实例工厂。IoC 容器的真正强大之处在于知道如何在对象被请求时自动解决它们的依赖关系。

例如,假设我有以下与实现匹配的接口:IRepository、ILoggingService、IDataService、IMessagingService、IAppController

一旦每个接口都注册了给定的具体类型,其中构造函数看起来像: Repository(IDataService dataService, ILoggingService loggingService)
MessagingService(ILoggingService loggingService)
AppController(IRepository repository, IMessagingService messingService)

注册每个看起来像:

MyContainer.Register<LoggingService>().As<ILoggingService>();
MyContainer.Register<DataService>().As<IDataService>();
MyContainer.Register<MessagingService>().As<IMessagingService>();
MyContainer.Register<Repository>().As<IRepository>();
MyContainer.Register<AppController>().As<IAppController>();

等等

要获得应用控制器,我只需调用:

var controller = MyContainer.Resolve<IAppController>();

容器根据已注册的内容确定如何构造 IRepostory 和 IMessagingService 以及它们的所有依赖项。(如果不能,抛出一个异常,希望能指出开发人员没有正确设置。)

如果您想了解 IOC 容器内部发生的情况,请查看 Autofac。它是一个开源容器,但需要注意的是,IOC 容器中有很多复杂的代码。我觉得很奇怪,课程会尝试让学生使用 IoC 容器重新发明轮子。

于 2012-11-08T02:42:27.957 回答