ssannandeji / Zenject-2019

Dependency Injection Framework for Unity3D
MIT License
2.52k stars 363 forks source link

Zenject 5.5.1 InvalidOperationException #423

Closed marsermd closed 6 years ago

marsermd commented 6 years ago

After migrating from Zenject 5.4.0 to 5.5.1, I receive InvalidOperationException in DIContainer.ResolveDependencyRoots() in line foreach (var bindinPair in _providers)

InvalidOperationException: Collection was modified; enumeration operation may not execute.
System.ThrowHelper.ThrowInvalidOperationException (System.ExceptionResource resource) (at <c95265f74fdf4905bfb0d5a4b652216c>:0)
System.Collections.Generic.Dictionary`2+Enumerator[TKey,TValue].MoveNext () (at <c95265f74fdf4905bfb0d5a4b652216c>:0)
Zenject.DiContainer.ResolveDependencyRoots () (at Assets/AssetsFromStore/Zenject/Source/Main/DiContainer.cs:230)
Zenject.GameObjectContext.RunInternal () (at Assets/AssetsFromStore/Zenject/Source/Install/Contexts/GameObjectContext.cs:74)
Zenject.RunnableContext.Run () (at Assets/AssetsFromStore/Zenject/Source/Install/Contexts/RunnableContext.cs:36)
Zenject.RunnableContext.Initialize () (at Assets/AssetsFromStore/Zenject/Source/Install/Contexts/RunnableContext.cs:22)
Zenject.GameObjectContext.Construct (Zenject.DiContainer parentContainer) (at Assets/AssetsFromStore/Zenject/Source/Install/Contexts/GameObjectContext.cs:43)
System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <c95265f74fdf4905bfb0d5a4b652216c>:0)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <c95265f74fdf4905bfb0d5a4b652216c>:0)
System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) (at <c95265f74fdf4905bfb0d5a4b652216c>:0)
Zenject.DiContainer.InjectExplicitInternal (System.Object injectable, System.Type injectableType, Zenject.InjectArgs args) (at Assets/AssetsFromStore/Zenject/Source/Main/DiContainer.cs:1159)
Zenject.DiContainer.InjectExplicit (System.Object injectable, System.Type injectableType, Zenject.InjectArgs args) (at Assets/AssetsFromStore/Zenject/Source/Main/DiContainer.cs:1046)
Zenject.DiContainer.InjectExplicit (System.Object injectable, System.Collections.Generic.List`1[T] extraArgs) (at Assets/AssetsFromStore/Zenject/Source/Main/DiContainer.cs:1008)
Zenject.DiContainer.Inject (System.Object injectable, System.Collections.Generic.IEnumerable`1[T] extraArgs) (at Assets/AssetsFromStore/Zenject/Source/Main/DiContainer.cs:1794)
Zenject.DiContainer.Inject (System.Object injectable) (at Assets/AssetsFromStore/Zenject/Source/Main/DiContainer.cs:1788)
Zenject.DiContainer.InjectGameObject (UnityEngine.GameObject gameObject) (at Assets/AssetsFromStore/Zenject/Source/Main/DiContainer.cs:1706)
Zenject.DiContainer.InstantiatePrefab (UnityEngine.Object prefab, Zenject.GameObjectCreationParameters gameObjectBindInfo) (at Assets/AssetsFromStore/Zenject/Source/Main/DiContainer.cs:1537)
Zenject.DiContainer.InstantiatePrefab (UnityEngine.Object prefab) (at Assets/AssetsFromStore/Zenject/Source/Main/DiContainer.cs:1503)
Multiplayer.DistributedObjectFactory`2[TModel,TObject].Create (TModel model) (at Assets/scripts/Multiplayer/MultiplayerFramework/Factory/DistributedObjectFactory.cs:39)
Zenject.FactoryProvider`3+<GetAllInstancesWithInjectSplit>c__Iterator0[TParam1,TValue,TFactory].MoveNext () (at Assets/AssetsFromStore/Zenject/Source/Providers/FactoryProvider.cs:122)
Zenject.IProviderExtensions.GetAllInstances (Zenject.IProvider creator, Zenject.InjectContext context, System.Collections.Generic.List`1[T] args) (at Assets/AssetsFromStore/Zenject/Source/Providers/IProviderExtensions.cs:29)
Zenject.IProviderExtensions.GetInstance (Zenject.IProvider creator, Zenject.InjectContext context, System.Collections.Generic.List`1[T] args) (at Assets/AssetsFromStore/Zenject/Source/Providers/IProviderExtensions.cs:75)
Zenject.PlaceholderFactory`1[TValue].CreateInternal (System.Collections.Generic.List`1[T] extraArgs) (at Assets/AssetsFromStore/Zenject/Source/Factories/PlaceholderFactory.cs:32)
Rethrow as ZenjectException: Error during construction of type 'Ostrich' via Factory`2.Create method!
Zenject.PlaceholderFactory`1[TValue].CreateInternal (System.Collections.Generic.List`1[T] extraArgs) (at Assets/AssetsFromStore/Zenject/Source/Factories/PlaceholderFactory.cs:40)
Zenject.Factory`2[TParam1,TValue].Create (TParam1 param) (at Assets/AssetsFromStore/Zenject/Source/Factories/Factory.cs:38)
Multiplayer.ServerObjectSystem`3[TWorldModel,TObjectModel,TObjectFacade].AddObject (TObjectModel model) (at Assets/scripts/Multiplayer/MultiplayerFramework/Systems/Server/ServerObjectSystem.cs:32)
Server.OnConnected (LiteNetLib.NetPeer peer) (at Assets/scripts/Multiplayer/Common/WebActors/Server.cs:170)
LiteNetLib.EventBasedNetListener.LiteNetLib.INetEventListener.OnPeerConnected (LiteNetLib.NetPeer peer) (at Assets/scripts/Externals/ClericusCommon/3rdParty/LiteNetLib/INetEventListener.cs:93)
LiteNetLib.NetManager.ProcessEvent (LiteNetLib.NetManager+NetEvent evt) (at Assets/scripts/Externals/ClericusCommon/3rdParty/LiteNetLib/NetManager.cs:356)
LiteNetLib.NetManager.PollEvents () (at Assets/scripts/Externals/ClericusCommon/3rdParty/LiteNetLib/NetManager.cs:879)
Server.FixedUpdate () (at Assets/scripts/Multiplayer/Common/WebActors/Server.cs:235)

This happens when I try to add a binding to a parent container from it's sub-container (during InstallBindings stage of both of the containers).

Minimal example is in progress.

Unity version: 2017.3.1f1 with .NET 4.6

marsermd commented 6 years ago

Probably not related to Zenject Tests Integration Tests failing

marsermd commented 6 years ago

In this case the minimal example turned out to be really tiny:)

public class BadInstaller : MonoInstaller
{
    public class Foo
    {
        [Inject]
        public void Init(Bar bar)
        {
            Debug.Log("init");
        }
    }

    public class Bar
    {

    }

    public override void InstallBindings()
    {
        Debug.Log("started!");
        Container.Bind<Foo>().FromSubContainerResolve().ByMethod(InstallSubContainer).AsSingle().NonLazy();
        Debug.Log("finished!");
    }

    private void InstallSubContainer(DiContainer sub)
    {
        sub.BindInterfacesAndSelfTo<Foo>().AsSingle();
        //Note that here we are binding to the parent container
        Container.Bind<Bar>().ToSelf().AsSingle();
    }
}
svermeulen commented 6 years ago

Thanks for the small reproducible example, that always really helps

Binding to a parent container from within a subcontainer installer method is not something I expected anyone to be doing :) Not really sure why you would need/want to do that. But in any case it's fixed now on master branch with the above commit