繁体   English   中英

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

[英]Operation is not valid due to the current state of the object

我是一名学生,我的工作是建立自己的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));
}

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

如果您只是刚开始,那么对IOC容器进行反向工程并不是您真正应该解决的事情。 我已经重新实现了您提供的代码,填补了一些空白,但是从我的眼中可以看出,您错过了容器的意义。

class Mkontener: UnresolvedDependenciesException, IContainer

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

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

您的实现都不做。 注册需要接受具体类型和接口类型。 系统会告知Resolve使用哪个接口,然后构造(或返回)已注册具体类型的实例。 像您要编写的内容这样的简单示例只不过是一个动态实例工厂。 IoC容器的真正功能在于知道如何在请求对象时自动解决它们的依赖关系。

例如,给定我具有以下与实现相匹配的接口:IRepository,ILoggingService,IDataService,IMessagingService,IAppController

使用给定的具体类型注册每个接口后,构造函数将如下所示:Repository(IDataService dataService,ILoggingService loggingService)
MessagingService(ILoggingService loggingService)
AppController(IRepository存储库,IMessagingService messagesService)

注册每个看起来像:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM