9

Unity3D はゲームオブジェクトを使用します。これらのゲーム オブジェクトにコンポーネントを追加します。コンポーネントは、基本クラスを継承する (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; }
}

ゲーム オブジェクトが作成され、ComponentWrapper がアタッチされていることを Unity エディターで確認できますが、Ninject が null ref エラーをスローするので、わかりません。プロセスを混乱させている 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)
4

3 に答える 3

6

Ninject は、オブジェクトが作成された後にアクティベーション アクションを実行します。この場合は、プロパティ インジェクションのアクティブ化アクションです。オブジェクトのプロパティに inject 属性がある場合、その情報を取得しようとするリフレクション部分に問題があるようです。おそらくそれはNinjectのバグです。しかし、さらに調査するには、いくつかの情報が必要です。

  1. Ninject の最新バージョン (2.2.1.0) を使用していますか?
  2. どのバージョンを正確に使用していますか? (例: .NET 4.0 NoWeb)
  3. Ninject の StandardInjectionHeuristic.ShouldInject をデバッグして、問題の原因となっているプロパティを調査できますか? そして、このプロパティの何が特別なのかを見てください? (たとえば、オーバーライドされた仮想プロパティですか、同じ名前の他のプロパティがありますか、それはインデクサーですか...)
于 2011-03-15T09:59:32.640 に答える
5

この記事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 コンテナーの概念をよりよく理解できました。

于 2012-11-06T13:41:34.037 に答える
0

Unity3Dプロジェクトでもninjectを使用したかったので、これについて何か追加したいと思います(私の問題は異なる可能性があります)。

残念ながら、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 に対して十分に軽量ではないと思います:/

于 2012-02-08T18:12:35.593 に答える