2010-04-06 2 views
2

У меня возникли трудности с интеграцией Ninject с XNA.Как использовать Ninject с 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 

Когда я пытаюсь получить CachedContentLoader, я получаю исключение переполнения стека. Я основываю это на этом tutorial, но я действительно не знаю, что делаю. Помогите?

ответ

0

Возможно, у вас есть круговая ссылка в одной из ваших настроенных зависимостей. Поэтому, когда ninject пытается создать экземпляр класса, о котором идет речь, он переходит в бесконечный цикл инъекции.

Я не просматривал ваши классы, чтобы посмотреть, что это может быть, но я бы предложил поставить точку останова в конструкторе каждого из классов, которые вы определили в GameModule.Load. Это должно стать довольно очевидным, как только вы увидите, где происходит вложенное создание экземпляра.