Ninject с Unity3D - PullRequest
       6

Ninject с Unity3D

9 голосов
/ 15 марта 2011

Unity3D использует GameObjects.Вы добавляете компоненты к этим игровым объектам, где компонент - это скрипт (в c # или js), который наследует базовый класс.Само Unity написано в нативном коде.Компоненты не могут иметь конструктор, и вместо этого используют отражение, чтобы определить, есть ли у вас определенные именованные методы (OnStart, Update и т. Д.).

Вместо того, чтобы у меня кровоточили глаза из-за отсутствия конструкторов и других действительно раздражающих вещейЯ подумал, что мог бы сделать следующее:

public class SomeGameBehaviour
{
    public SomeGameBehaviour(IGameObject gameObject) { }
}

(Monobehaviour - базовый класс)

public class ComponentWrapper : MonoBehaviour, IGameObject { }

.. тогда я мог бы получить gameObject.Transform или что-то еще из SomeGameBehaviour,отделяя его от принудительного запаздывания Unity.

Проблема: я не смог использовать поведение по умолчанию, потому что у Components / MonoBehaviours нет и не может быть конструкторов - он выдает ошибки, если вы попытаетесь,поэтому я свернул свой собственный провайдер.

public class UnityProvider : IProvider
{
    public object Create(IContext context)
    {
        var go = new GameObject(context.Request.Target.Name, typeof(ComponentWrapper));
        var c = go.GetComponent<ComponentWrapper>();

        return c;
    }

    public Type Type { get; private set; }
}

Я вижу в редакторе Unity, что игровой объект создается, и ComponentWrapper присоединяется, однако Ninject выдает мне пустую ошибку ref, которую я не могу понять,Кажется, что он делает дальнейшие действия либо с IGameObject, либо с Target, который расстраивает процесс.

NullReferenceException: Object reference not set to an instance of an object
Ninject.Infrastructure.Language.ExtensionsForMemberInfo.GetParentDefinition (System.Reflection.MethodInfo method, BindingFlags flags)
Ninject.Infrastructure.Language.ExtensionsForMemberInfo.GetParentDefinition (System.Reflection.PropertyInfo property)
Ninject.Infrastructure.Language.ExtensionsForMemberInfo.IsDefined (System.Reflection.PropertyInfo element, System.Type attributeType, Boolean inherit)
Ninject.Infrastructure.Language.ExtensionsForMemberInfo.HasAttribute (System.Reflection.MemberInfo member, System.Type type)
Ninject.Selection.Heuristics.StandardInjectionHeuristic.ShouldInject (System.Reflection.MemberInfo member)
Ninject.Selection.Selector+<>c__DisplayClass3.<SelectPropertiesForInjection>b__2 (IInjectionHeuristic h)
System.Linq.Enumerable.Any[IInjectionHeuristic] (IEnumerable`1 source, System.Func`2 predicate)
Ninject.Selection.Selector.<SelectPropertiesForInjection>b__1 (System.Reflection.PropertyInfo p)
System.Linq.Enumerable+<CreateWhereIterator>c__Iterator1D`1[System.Reflection.PropertyInfo].MoveNext ()
System.Collections.Generic.List`1[System.Reflection.PropertyInfo].AddEnumerable (IEnumerable`1 enumerable)
System.Collections.Generic.List`1[System.Reflection.PropertyInfo].AddRange (IEnumerable`1 collection)
Ninject.Selection.Selector.SelectPropertiesForInjection (System.Type type)
Ninject.Planning.Strategies.PropertyReflectionStrategy.Execute (IPlan plan)
Ninject.Planning.Planner+<>c__DisplayClass2.<GetPlan>b__0 (IPlanningStrategy s)
Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map[IPlanningStrategy] (IEnumerable`1 series, System.Action`1 action)
Ninject.Planning.Planner.GetPlan (System.Type type)
Ninject.Activation.Context.Resolve ()
Ninject.KernelBase.<Resolve>b__4 (IContext context)
System.Linq.Enumerable+<CreateSelectIterator>c__Iterator10`2[Ninject.Activation.IContext,System.Object].MoveNext ()
System.Linq.Enumerable.Single[Object] (IEnumerable`1 source, System.Func`2 predicate, Fallback fallback)
System.Linq.Enumerable.SingleOrDefault[Object] (IEnumerable`1 source)
Ninject.Planning.Targets.Target`1[T].GetValue (System.Type service, IContext parent)
Ninject.Planning.Targets.Target`1[T].ResolveWithin (IContext parent)
Ninject.Activation.Providers.StandardProvider.GetValue (IContext context, ITarget target)
Ninject.Activation.Providers.StandardProvider+<>c__DisplayClass2.<Create>b__1 (ITarget target)
System.Linq.Enumerable+<CreateSelectIterator>c__Iterator10`2[Ninject.Planning.Targets.ITarget,System.Object].MoveNext ()
System.Collections.Generic.List`1[System.Object].AddEnumerable (IEnumerable`1 enumerable)
System.Collections.Generic.List`1[System.Object]..ctor (IEnumerable`1 collection)
System.Linq.Enumerable.ToArray[Object] (IEnumerable`1 source)
Ninject.Activation.Providers.StandardProvider.Create (IContext context)
Ninject.Activation.Context.Resolve ()
Ninject.KernelBase.<Resolve>b__4 (IContext context)
System.Linq.Enumerable+<CreateSelectIterator>c__Iterator10`2[Ninject.Activation.IContext,System.Object].MoveNext ()
System.Linq.Enumerable+<CreateCastIterator>c__Iterator0`1[SomeGameBehaviour].MoveNext ()
System.Linq.Enumerable.Single[SomeGameBehaviour] (IEnumerable`1 source, System.Func`2 predicate, Fallback fallback)
System.Linq.Enumerable.Single[SomeGameBehaviour] (IEnumerable`1 source)
Ninject.ResolutionExtensions.Get[SomeGameBehaviour] (IResolutionRoot root, Ninject.Parameters.IParameter[] parameters)
ObjectFactory.GetInstance[SomeGameBehaviour] () (at Assets/Scripts/Core/ObjectFactory.cs:31)
Grid.Start () (at Assets/Scripts/World/Grid.cs:27)

Ответы [ 3 ]

6 голосов
/ 15 марта 2011

Ninject выполняет действия активации после создания объекта.В данном случае это свойство активации активации действия.Кажется, что существует проблема в части отражения, которая пытается получить информацию, если есть атрибут inject для свойства вашего объекта.Вероятно, это ошибка в Ninject.Но для дальнейшего изучения мне нужна информация:

  1. Вы используете последнюю версию Ninject (2.2.1.0)?
  2. Какую версию вы используете именно?(например .NET 4.0 NoWeb)
  3. Можете ли вы отладить StandardInjectionHeuristic.ShouldInject для Ninject и выяснить, какое свойство вызывает проблему?И посмотрите, что особенного в этом свойстве?(например, это виртуальное свойство, которое переопределяется, есть ли другие свойства с тем же именем, это индексатор, ...)
5 голосов
/ 06 ноября 2012

Автору этой статьи http://outlinegames.com/2012/08/29/on-testability/ удалось портировать Ninject на Unity и он назвал его Uniject: https://github.com/banderous/Uniject

Однако я хочу указать и на мое (простое) решение:

http://blog.sebaslab.com/ioc-container-for-unity3d-part-1/
http://blog.sebaslab.com/ioc-container-for-unity3d-part-2/

Мне все еще нужно поблагодарить Remo Gloor, потому что благодаря ему я лучше понял концепцию контейнера IoC.

0 голосов
/ 08 февраля 2012

Я хочу добавить кое-что по этому поводу (хотя моя проблема может быть другой), поскольку я хотел использовать ninject и в проекте Unity3D.

К несчастью, Ninject не работает в Unity 3D 3.5 как с использованием скомпилированной версии для разработчиков, так и с исходным кодом (2.2.1).

Однако, используя исходный код, я понял причину: сначала мне пришлось вручную отключить весь код, связанный с определением NOWEB (к сожалению, Unity3D не поддерживает определения уровня компиляции, если я не ошибаюсь), но настоящий сбой происходит потому, что связанного кода NO_ASSEMBLY_SCANNING. Именно в Kernel.cs по этим строкам:

#if !NO_ASSEMBLY_SCANNING
            if (this.Settings.LoadExtensions)
            {
                this.Load(new[] { this.Settings.ExtensionSearchPattern });
            }
#endif

Я также попытался отключить это определение, а затем Unity3D перестал жаловаться. Хотя после того, как я это сделал, инъекция перестала работать:

StandardKernel kernel = new StandardKernel();   

kernel.Bind<IKernel>().ToMethod(context => kernel);

kernel.Inject(ObjectWhichNeedsKernel)

это не сработало, ObjectWhichNeedsKernel не вставил IKernel, но это может быть просто мой код неправильно.

Так что я думаю, что Ninject недостаточно легок для Unity3D: /

...