Unity3D中使用Zenject绑定接口到MonoBehaviour报错,求原因及解决办法
问题场景
我是Zenject新手,尝试将接口绑定到MonoBehaviour以在Player中模拟播放音效,编写了如下代码:
GameInstaller代码
using UnityEngine; using Zenject; public class GameInstaller : MonoInstaller { public override void InstallBindings() { Container.Bind<IAudioService>().To<AudioController>().AsSingle(); } }
Player代码
using UnityEngine; using Zenject; public class Player : MonoBehaviour { [Inject] private IAudioService _audioService; private void Start() { _audioService.Play(); } }
AudioController代码
using UnityEngine; public class AudioController : MonoBehaviour, IAudioService { public void Play() { Debug.Log("Audio called"); } }
运行后出现报错:
ZenjectException: Assert hit! Error occurred while instantiating object of type 'AudioController'. Instantiator should not be used to create new mono behaviours. Must use InstantiatePrefabForComponent, InstantiatePrefab, or InstantiateComponent.
但把AudioController改成非MonoBehaviour类就能正常运行,请问这是为什么?
原因解释
Unity的MonoBehaviour对象不能用普通的new关键字创建,必须依附于GameObject存在——要么挂载到已有的GameObject上,要么通过Unity的Instantiate方法实例化预制体或组件。
你当前用的Bind<IAudioService>().To<AudioController>().AsSingle()绑定方式,Zenject会尝试用常规的C#对象实例化逻辑(类似new AudioController())来创建实例,这完全违背了Unity对MonoBehaviour的创建规则,所以直接触发报错。
而如果把AudioController改成普通C#类,它不需要依赖GameObject,Zenject可以用常规方式实例化,自然就不会有问题。
解决办法
如果要保留AudioController作为MonoBehaviour,需要调整Zenject的绑定逻辑,让它遵循Unity的实例化规则,常见方案有三种:
方案1:绑定场景中已存在的实例
如果场景里已经有一个挂载了AudioController的GameObject,直接绑定这个现成的实例:
public class GameInstaller : MonoInstaller { public AudioController audioController; // 在Inspector面板拖入场景中的实例 public override void InstallBindings() { Container.Bind<IAudioService>().FromInstance(audioController).AsSingle(); } }
方案2:动态创建GameObject并挂载组件
让Zenject自动创建新的GameObject,然后把AudioController挂载上去:
public class GameInstaller : MonoInstaller { public override void InstallBindings() { Container.Bind<IAudioService>().To<AudioController>().FromNewComponentOnNewGameObject().AsSingle(); } }
方案3:从预制体实例化组件
如果AudioController是预制体的一部分,用预制体来实例化:
public class GameInstaller : MonoInstaller { public GameObject audioPrefab; // 预制体上已挂载AudioController组件 public override void InstallBindings() { Container.Bind<IAudioService>().FromComponentInNewPrefab(audioPrefab).AsSingle(); } }
内容的提问来源于stack exchange,提问作者user12741739

