2010-04-06 7 views
2

J'ai de la difficulté à intégrer Ninject avec XNA.Comment utiliser Ninject avec XNA?

static class Program 
{ 
    /** 
    * The main entry point for the application. 
    */ 
    static void Main(string[] args) 
    { 
     IKernel kernel = new StandardKernel(NinjectModuleManager.GetModules()); 
     CachedContentLoader content = kernel.Get<CachedContentLoader>(); // stack overflow here 
     MasterEngine game = kernel.Get<MasterEngine>(); 
     game.Run(); 
    } 
} 

    // constructor for the game 
    public MasterEngine(IKernel kernel) 
     : base(kernel) 
    { 
     this.inputReader = kernel.Get<IInputReader>(); 

     graphicsDeviceManager = kernel.Get<GraphicsDeviceManager>(); 
     Components.Add(kernel.Get<GamerServicesComponent>()); 

     // Tell the loader to look for all files relative to the "Content" directory. 
     Assets = kernel.Get<CachedContentLoader>(); 

     //Sets dimensions of the game window 
     graphicsDeviceManager.PreferredBackBufferWidth = 800; 
     graphicsDeviceManager.PreferredBackBufferHeight = 600; 
     graphicsDeviceManager.ApplyChanges(); 

     IsMouseVisible = false; 
    } 

Ninject.cs:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using Ninject.Modules; 
using HWAlphaRelease.Controller; 
using Microsoft.Xna.Framework; 
using Nuclex.DependencyInjection.Demo.Scaffolding; 
using Microsoft.Xna.Framework.Content; 
using Microsoft.Xna.Framework.Graphics; 

namespace HWAlphaRelease 
{ 
    public static class NinjectModuleManager 
    { 

     public static NinjectModule[] GetModules() 
     { 
      return new NinjectModule[1] { new GameModule() }; 
     } 

     /// <summary>Dependency injection rules for the main game instance</summary> 
     public class GameModule : NinjectModule 
     { 

      #region class ServiceProviderAdapter 

      /// <summary>Delegates to the game's built-in service provider</summary> 
      /// <remarks> 
      /// <para> 
      ///  When a class' constructor requires an IServiceProvider, the dependency 
      ///  injector cannot just construct a new one and wouldn't know that it has 
      ///  to create an instance of the Game class (or take it from the existing 
      ///  Game instance). 
      /// </para> 
      /// <para> 
      ///  The solution, then, is this small adapter that takes a Game instance 
      ///  and acts as if it was a freely constructable IServiceProvider implementation 
      ///  while in reality, it delegates all lookups to the Game's service container. 
      /// </para> 
      /// </remarks> 
      private class ServiceProviderAdapter : IServiceProvider 
      { 

       /// <summary>Initializes a new service provider adapter for the game</summary> 
       /// <param name="game">Game the service provider will be taken from</param> 
       public ServiceProviderAdapter(Game game) 
       { 
        this.gameServices = game.Services; 
       } 

       /// <summary>Retrieves a service from the game service container</summary> 
       /// <param name="serviceType">Type of the service that will be retrieved</param> 
       /// <returns>The service that has been requested</returns> 
       public object GetService(Type serviceType) 
       { 
        return this.gameServices; 
       } 

       /// <summary>Game services container of the Game instance</summary> 
       private GameServiceContainer gameServices; 

      } 

      #endregion // class ServiceProviderAdapter 

      #region class ContentManagerAdapter 

      /// <summary>Delegates to the game's built-in ContentManager</summary> 
      /// <remarks> 
      /// This provides shared access to the game's ContentManager. A dependency 
      /// injected class only needs to require the ISharedContentService in its 
      /// constructor and the dependency injector will automatically resolve it 
      /// to this adapter, which delegates to the Game's built-in content manager. 
      /// </remarks> 
      private class ContentManagerAdapter : ISharedContentService 
      { 

       /// <summary>Initializes a new shared content manager adapter</summary> 
       /// <param name="game">Game the content manager will be taken from</param> 
       public ContentManagerAdapter(Game game) 
       { 
        this.contentManager = game.Content; 
       } 

       /// <summary>Loads or accesses shared game content</summary> 
       /// <typeparam name="AssetType">Type of the asset to be loaded or accessed</typeparam> 
       /// <param name="assetName">Path and name of the requested asset</param> 
       /// <returns>The requested asset from the the shared game content store</returns> 
       public AssetType Load<AssetType>(string assetName) 
       { 
        return this.contentManager.Load<AssetType>(assetName); 
       } 

       /// <summary>The content manager this instance delegates to</summary> 
       private ContentManager contentManager; 

      } 

      #endregion // class ContentManagerAdapter 

      /// <summary>Initializes the dependency configuration</summary> 
      public override void Load() 
      { 

       // Allows access to the game class for any components with a dependency 
       // on the 'Game' or 'DependencyInjectionGame' classes. 
       Bind<MasterEngine>().ToSelf().InSingletonScope(); 
       Bind<NinjectGame>().To<MasterEngine>().InSingletonScope(); 
       Bind<Game>().To<MasterEngine>().InSingletonScope(); 

       // Let the dependency injector construct a graphics device manager for 
       // all components depending on the IGraphicsDeviceService and 
       // IGraphicsDeviceManager interfaces 
       Bind<GraphicsDeviceManager>().ToSelf().InSingletonScope(); 
       Bind<IGraphicsDeviceService>().To<GraphicsDeviceManager>().InSingletonScope(); 
       Bind<IGraphicsDeviceManager>().To<GraphicsDeviceManager>().InSingletonScope(); 

       // Some clever adapters that hand out the Game's IServiceProvider and allow 
       // access to its built-in ContentManager 
       Bind<IServiceProvider>().To<ServiceProviderAdapter>().InSingletonScope(); 
       Bind<ISharedContentService>().To<ContentManagerAdapter>().InSingletonScope(); 

       Bind<IInputReader>().To<UserInputReader>().InSingletonScope().WithConstructorArgument("keyMapping", Constants.DEFAULT_KEY_MAPPING); 
       Bind<CachedContentLoader>().ToSelf().InSingletonScope().WithConstructorArgument("rootDir", "Content"); 

      } 

     } 

    } 

} 

NinjectGame.cs

/// <summary>Base class for Games making use of Ninject</summary> 
    public class NinjectGame : Game { 

    /// <summary>Initializes a new Ninject game instance</summary> 
    /// <param name="kernel">Kernel the game has been created by</param> 
    public NinjectGame(IKernel kernel) { 
     Type ownType = this.GetType(); 

     if(ownType != typeof(Game)) { 
     kernel.Bind<NinjectGame>().To<MasterEngine>().InSingletonScope(); 
     } 

     kernel.Bind<Game>().To<NinjectGame>().InSingletonScope(); 
    } 

    } 

} // namespace Nuclex.DependencyInjection.Demo.Scaffolding 

Lorsque je tente d'obtenir le CachedContentLoader, je reçois une exception de débordement de pile. Je me base sur ce tutorial, mais je n'ai vraiment aucune idée de ce que je fais. Aidez-moi?

Répondre

0

Vous avez probablement une référence circulaire dans l'une de vos dépendances configurées. Ainsi, lorsque ninject essaie d'instancier la classe en question, il se retrouve dans une boucle d'injection sans fin.

Je n'ai pas regardé vos classes pour voir ce que cela pourrait être, mais je suggérerais de mettre un point d'arrêt dans le constructeur de chacune des classes que vous avez définies dans GameModule.Load. Cela devrait devenir évident dès que vous pouvez voir où se passe l'instanciation imbriquée.