首页 文章

Ninject与Unity3D

提问于
浏览
9

Unity3D使用GameObjects . 您可以向这些游戏对象添加组件,其中组件是继承基类的脚本(在c#或js中) . Unity本身是用本机代码编写的 . 组件不能有构造函数,而是使用反射来查找是否有某些命名方法(OnStart,Update等) .

我认为我可以做以下事情,而不是让我的眼睛因为缺乏构造函数和其他非常讨厌的东西而流血 .

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

(Monobehaviour是基类)

public class ComponentWrapper : MonoBehaviour, IGameObject { }

..然后我可以从SomeGameBehaviour获取gameObject.Transform或者你有什么东西,同时将它与Unity强制延迟解耦 .

问题:我无法使用默认的注入行为,因为Components / MonoBehaviours没有,也没有构造函数 - 如果你尝试,它会抛出错误,所以我推出了自己的Provider .

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会向我抛出一个空引用错误,这是我无法弄清楚的 . 它似乎正在为IGameObject或目标做进一步的事情,这会扰乱这个过程 .

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 回答

  • 5

    Ninject在创建对象后执行激活操作 . 在这种情况下,它是属性注入激活动作 . 似乎反射部分中存在一个问题,即如果对象的属性上存在inject属性,则尝试获取信息 . 可能这是Ninject中的一个错误 . 但为了进一步调查,我需要一些信息:

    • 您是否使用最新版本的Ninject(2.2.1.0)?

    • 您准确使用哪个版本? (例如.NET 4.0 NoWeb)

    • 你可以调试Ninject的StandardInjectionHeuristic.ShouldInject并调查导致问题的属性吗?看看这个房产有什么特别之处? (例如,它是被覆盖的虚拟属性,是否存在具有相同名称的其他属性,是否为索引器,...)

  • 6

    本文作者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

    我想在此添加一些内容(虽然我的问题可能有所不同),因为我也希望在Unity3D项目中使用ninject .

    不幸的是,Ninject在Unity 3D 3.5中无法使用mono develop编译版本和源代码(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来说不够轻巧:/

相关问题