Zenject (Unity) как передать сущность который наследуется от MonoBehaviour?

public sealed class GameInstaller : MonoInstaller
{

    public override void InstallBindings()
    {
        this.Container
            .Bind<Lavash>()
            .FromNew()
            .AsSingle();
     }
}

public class Ingredient : MonoBehaviour 
{
  private Lavash select ;   //этот класс наследуется от MonoBehaviour

   [Inject] 
   public void Construct(Lavash _select) 
   { 
     select = _select;  
   }
}

Если убрать MonoBehaviour из класса "Lavash " то всё работает. Но мне он нужен.

Если не убрать, то такие ошибки:

1)

ZenjectException: Assert hit! Invalid type given during bind command.  Expected type 'Lavash' to NOT derive from UnityEngine.Component 
ModestTree.Assert.That (System.Boolean condition, System.String message, System.Object p1) (at Assets/Plugins/Zenject/Source/Internal/Assert.cs:347) 
Zenject.BindingUtil.AssertIsNotComponent (System.Type type) (at Assets/Plugins/Zenject/Source/Binding/BindingUtil.cs:78) 
Zenject.BindingUtil.AssertTypesAreNotComponents (System.Collections.Generic.IEnumerable`1[T] types) (at Assets/Plugins/Zenject/Source/Binding/BindingUtil.cs:117) 
Zenject.FromBinder.FromNew () (at Assets/Plugins/Zenject/Source/Binding/Binders/FromBinders/FromBinder.cs:63) 
GameInstaller.InstallBindings () (at Assets/Scripts/GameInstaller.cs:12) 
Zenject.Context.InstallInstallers (System.Collections.Generic.List`1[T] normalInstallers, System.Collections.Generic.List`1[T] normalInstallerTypes, System.Collections.Generic.List`1[T] scriptableObjectInstallers, System.Collections.Generic.List`1[T] installers, System.Collections.Generic.List`1[T] installerPrefabs) (at Assets/Plugins/Zenject/Source/Install/Contexts/Context.cs:218) 
Zenject.Context.InstallInstallers () (at Assets/Plugins/Zenject/Source/Install/Contexts/Context.cs:139) 
Zenject.SceneContext.InstallBindings (System.Collections.Generic.List`1[T] injectableMonoBehaviours) (at Assets/Plugins/Zenject/Source/Install/Contexts/SceneContext.cs:346) 
Zenject.SceneContext.Install () (at Assets/Plugins/Zenject/Source/Install/Contexts/SceneContext.cs:265) 
Zenject.SceneContext.Validate () (at Assets/Plugins/Zenject/Source/Install/Contexts/SceneContext.cs:121) 
Zenject.Internal.ZenUnityEditorUtil.ValidateCurrentSceneSetup () (at Assets/Plugins/Zenject/Source/Editor/ZenUnityEditorUtil.cs:67) 
UnityEngine.Debug:LogException(Exception) 
ModestTree.Log:ErrorException(Exception) (at Assets/Plugins/Zenject/Source/Internal/Log.cs:60) 
Zenject.Internal.ZenUnityEditorUtil:ValidateCurrentSceneSetup() (at Assets/Plugins/Zenject/Source/Editor/ZenUnityEditorUtil.cs:72) 
Zenject.Internal.ZenUnityEditorUtil:ValidateAllActiveScenes() (at Assets/Plugins/Zenject/Source/Editor/ZenUnityEditorUtil.cs:96) 
Zenject.Internal.<>c:<ValidateAllActiveScenes>b__16_0() (at Assets/Plugins/Zenject/Source/Editor/ZenMenuItems.cs:262) 
Zenject.Internal.ZenUnityEditorUtil:SaveThenRunPreserveSceneSetup(Action) (at Assets/Plugins/Zenject/Source/Editor/ZenUnityEditorUtil.cs:26) 
Zenject.Internal.ZenMenuItems:ValidateAllActiveScenes() (at Assets/Plugins/Zenject/Source/Editor/ZenMenuItems.cs:260)

ZenjectException: Zenject Validation Failed!  See errors below for details. 
Zenject.Internal.ZenUnityEditorUtil.ValidateCurrentSceneSetup () (at Assets/Plugins/Zenject/Source/Editor/ZenUnityEditorUtil.cs:84) 
Zenject.Internal.ZenUnityEditorUtil.ValidateAllActiveScenes () (at Assets/Plugins/Zenject/Source/Editor/ZenUnityEditorUtil.cs:96) 
Zenject.Internal.ZenMenuItems+<>c.<ValidateAllActiveScenes>b__16_0 () (at Assets/Plugins/Zenject/Source/Editor/ZenMenuItems.cs:262) 
Zenject.Internal.ZenUnityEditorUtil.SaveThenRunPreserveSceneSetup (System.Action action) (at Assets/Plugins/Zenject/Source/Editor/ZenUnityEditorUtil.cs:26) 
UnityEngine.Debug:LogException(Exception) 
ModestTree.Log:ErrorException(Exception) (at Assets/Plugins/Zenject/Source/Internal/Log.cs:60) 
Zenject.Internal.ZenUnityEditorUtil:SaveThenRunPreserveSceneSetup(Action) (at Assets/Plugins/Zenject/Source/Editor/ZenUnityEditorUtil.cs:31)

Ответы (1 шт):

Автор решения: Vladimir

У MonoBehaviour есть несколько особенностей: во-первых, MonoBehaviour десериализуется Unity, а не создаётся с помощью конструктора; во-вторых, он не существует сам по себе, а идёт в связке с GameObject.


FromNew в Zenject является вариантом по умолчанию, т.е. код

Container
    .Bind<Lavash>()
    .FromNew()
    .AsSingle();

эквивалентен

Container
    .Bind<Lavash>()
    .AsSingle();

и создаёт он обычный объект класса через вызов его конструктора. Другими словами, для создания MonoBehaviour он не пригоден.


Простейшим решением будет просто создать всё из кода, что делается так:

Container
    .Bind<Lavash>()
    .FromNewComponentOnNewGameObject()
    .AsSingle();

Кроме того, если Ingredient находится не в сцене, а тоже создаётся в Installer'е, то для него нужно будет вызвать NonLazy

Container
    .Bind<Ingredient>()
    .FromNewComponentOnNewGameObject()
    .AsSingle()
    .NonLazy();

так как Zenject по умолчанию не создаёт то, что нигде не используется.


Тем не менее, наиболее часто используют две другие опции, загрузку из префаба:

[SerializeField] Lavash _lavash;

public override void InstallBindings() {
    Container
        .Bind<Lavash>()
        .FromComponentInNewPrefab(_lavash)
        .AsSingle();
}

для чего нужно создать префаб Lavash, где будет присутствовать компонент Lavash, и задать этот префаб инсталлеру; или из ресурса:

public override void InstallBindings() {
    Container
        .Bind<Lavash>()
        .FromComponentInNewPrefabResource("Lavash")
        .AsSingle();
}

для чего префаб Lavash нужно поместить в папку Resources.


Это не единственные доступные опции. Более того, способов, которыми можно решить эту задачу, довольно много. Другие варианты можно найти, например, в Readme и в CheatSheet Zenject'а.

→ Ссылка