Tengo una configuración de Unity + Zenject con un ProjectInstaller con algunas dependencias globales que se adhieren a una interfaz "modal", por ejemplo,
public class ProjectInstaller : MonoInstaller { public override void InstallBindings() { Container.Bind<ModalManager>().AsSingle(); Container.Bind<Modal>().To<DialogManager>().AsSingle(); } } Algunos modales solo son relevantes para ciertas escenas, por lo que los vinculo en SceneInstaller :
public class SceneInstaller : MonoInstaller { public override void InstallBindings() { Container.BindInterfacesAndSelfTo<InventoryManager>() .FromComponentInNewPrefab(InventoryPrefab) .AsSingle() } } Quiero administrar todos los modales desde el único ModalManager , definido en el alcance del proyecto. Entonces tiene un enlace List<Modal> :
public class ModalManager : MonoBehaviour { [Inject] protected List<Modal> _modals; } Cuando ejecuto esto, ModalManager solo obtiene un único modal: el definido en el alcance del proyecto. Según tengo entendido SceneContext es un subcontenedor de ProjectContext . Entonces, debería poder usar FromSubContainerResolve en ProjectInstaller para vincular elementos en la escena secundaria, quizás agregando una línea como:
// ProjectInstaller.cs public override void InstallBindings() { // ... Container.Bind<Modal>().To<InventoryManager>().FromSubContainerResolve(); } Pero no estoy seguro de cuál de los once métodos FromSubContainerResolve tiene sentido para este caso. Todos parecen pertinentes para prefabricados con un contexto de objeto de juego, no para usar desde ProjectContext .
¿Tiene sentido este caso de uso? ¿Hay una manera más fácil o mejor?
El problema es que ModalManager solo se puede inyectar con dependencias que se agregan directamente a ProjectContext. Para este tipo de problemas recomiendo utilizar el siguiente patrón:
public interface IModal { } public class ModalManager { private readonly List<IModal> _modals = new List<IModal>(); public IReadOnlyList<IModal> Modals { get { return _modals; } } public void AddModal(IModal modal) { _modals.Add(modal); } public bool RemoveModal(IModal modal) { return _modals.Remove(modal); } } public class ModalRegisterHandler : IInitializable, IDisposable { private readonly List<IModal> _modals; private readonly ModalManager _modalManager; public ModalRegisterHandler( // We need to use InjectSources.Local here, otherwise we will // add any project context modals again in each scene [Inject(Source = InjectSources.Local)] List<IModal> modals, ModalManager modalManager) { _modals = modals; _modalManager = modalManager; } public void Initialize() { foreach (var modal in _modals) { _modalManager.AddModal(modal); } } public void Dispose() { // We don't want ModalManager to retain references to Modals defined in unloaded scenes // (dispose is executed on scene unload) foreach (var modal in _modals) { _modalManager.RemoveModal(modal); } } } public class SceneInstaller : MonoInstaller { public override void InstallBindings() { Container.Bind<IModal>().To<FooModal>(); Container.Bind<IModal>().To<BarModal>(); } } public class ProjectInstaller : MonoInstaller { public override void InstallBindings() { // We use CopyIntoDirectSubContainers so that ModalRegisterHandler gets automatically added to every // scene context Container.BindInterfacesTo<ModalRegisterHandler>().AsSingle().CopyIntoDirectSubContainers(); Container.Bind<ModalManager>().AsSingle(); Container.Bind<IModal>().To<QuxModal>(); Container.Bind<IModal>().To<FizzModal>(); } }