Как использовать Ninject с XNA?

2

Мне сложно интегрировать 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>(); // Qaru 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 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 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 built-in ContentManager</summary>
            /// <remarks>
            ///   This provides shared access to the game 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 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 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, я получаю исключение. Я основываюсь на этом учебнике, но я действительно не знаю, что я делаю. Помощь?

Теги:
dependency-injection
ninject
xna

1 ответ

0

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню