由于对象的当前状态,操作无效

时间:2012-11-08 01:06:25

标签: c# inversion-of-control

我是学生,我的工作是建立自己的IoC容器。我已经阅读了一些教程/代码示例并最终创建了它但是当我尝试创建它的实例时,我会像主题一样得到异常。这是我的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));
}

抱歉笨拙的代码等。刚刚从这里开始。

1 个答案:

答案 0 :(得分:0)

如果您刚刚开始,尝试对IOC容器进行逆向工程并不是您应该尝试解决的问题。我已经重新实现了你提供的代码,填写了一些空白,但从我可以看到你错过了一个容器的位置。

class Mkontener: UnresolvedDependenciesException, IContainer

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

IOC容器的工作方式是: A)针对接口注册具体类型。 (并让容器在询问界面时弄清楚如何设置具体类型的新实例,并管理范围。即每个请求的单例与实例) B)针对接口注册具体实例。 (经典的单身人士行为)

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

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

一旦每个接口都注册了给定的具体类型,其中构造函数如下所示: 存储库(IDataService dataService,ILoggingService loggingService)
MessagingService(ILoggingService loggingService)
AppController(IRepository存储库,IMessagingService messagingService)

注册每个看起来像:

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容器重新发明轮子。