将 Ninject 与 Xna 4.0 集成

发布于 2024-12-28 04:37:35 字数 2475 浏览 1 评论 0原文

尝试将 Ninject 与 XNA 集成,但是我在尝试将其全部连接起来时遇到了一些痛苦。

问题是我试图按照我认为应该做的那样去做,所以我尽可能地解耦事物以使其更加模块化,而 Xna 对我这样做并不满意。一个例子是 Game 对象在内部更新了很多事情,其中​​很多事情可以通过传递给我的对象来完成。因此,我决定将这些作为构造函数参数添加到 Game 类中,这样我就可以设置所有依赖项,然后使用 Ninject 为我提供所有依赖项均已解析的 Game 实例。

不幸的是,在这个例子中,通常XNA不会更新它的SpriteBatch,直到它到达Initilize阶段,我认为这是因为它需要GraphicsDeviceManager来获取窗口句柄来创建GraphicsDevice,然后才能公开它以供任何使用。 ..

因此,它们不能被注入到游戏中,因为它需要先做它的事情,而且我不能在游戏制作后真正将它们推入游戏中,因为我需要像世界组件这样的其他东西注入诸如好并推入游戏。

此时我想也许我可以创建自己的 GraphicsDevice,但由于我需要句柄,所以我也需要创建自己的窗口,后来我意识到 XNA 无论如何都会处理并重新创建它。所以它给我留下了可怕的味道......因为我不喜欢重写 Game 和 GraphicsDeviceManager 类,这将需要我重写许多其他功能,因为它们都是 XNA 程序集的内部功能。那么

是否有人能够在无需重写大量 XNA 的情况下设置依赖注入呢?

这是我当前模块的一个示例:

public class XnaModule : NinjectModule
{
    public override void Load()
    {
        Kernel.Bind<IServiceProvider>().To<NinjectServiceProvider>().InSingletonScope();
        Kernel.Bind<IGraphicsDeviceService>().To<GraphicsDeviceManager>().InSingletonScope();
        Kernel.Bind<ContentManager>().ToSelf().InSingletonScope();
        Kernel.Bind<SpriteBatch>().ToSelf().InSingletonScope();

        var contentManager = new ContentManager(Kernel.Get<IServiceProvider>());
        contentManager.RootDirectory = "Content";
        Kernel.Bind<ContentManager>().ToConstant(contentManager).InSingletonScope();

        var game = new MyGame(Kernel.Get<IGraphicsDeviceService>() as GraphicsDeviceManager,
                                    Kernel.Get<SpriteBatch>(), contentManager);
        Kernel.Bind<Game>().ToConstant(game).InSingletonScope();
    }
}

然后是游戏构造函数:

public class MyGame : Game
{
    public SpriteBatch SpriteBatch { get; private set; }
    public GraphicsDeviceManager Graphics { get; private set; }

    public MyGame(GraphicsDeviceManager graphics, SpriteBatch spriteBatch, ContentManager contentManager)
    {
        Graphics = graphics;
        SpriteBatch = spriteBatch;
        Content = contentManager;
    }

    // Other stuffs
}

两者都只是示例,因此您可以看到我正在采用的方法,当我自己新建游戏时,该模块绕过了循环依赖问题。我已经排除了 GameModule,它包含我的实际 Game 对象的依赖项,即工厂、gui 组件等,问题是它们最终也需要注入到 Game 中,然后我们就有了一个 catch22。

因为在解决依赖关系之前它们无法注入,但在开始游戏之前你无法解决依赖关系......这似乎是一种双输的情况。那么谁能告诉我他们是如何解决这个问题的呢?

我确实找到了 http://steveproxna01di.codeplex.com/ 但正在寻找是否还有更多这样的示例更多的是一种服务定位器方法,而不是注入方法。

Trying to integrate Ninject with XNA however I am having a bit of pain trying to get it all hooked up.

The problem is I am trying to do it as I think it should done, so I am decoupling things as much as possible to make it more modular, and Xna isn't happy with me doing this... an example of this is where the Game object news up a lot of things internally, and a lot of those things could do with being passed around to my objects. So I decided to add these as constructor arguments to the Game class, so I can setup all the dependencies then use Ninject to give me the Game instance with all its dependencies resolved.

Unfortunately In this example normally XNA doesn't new up its SpriteBatch until it has gotten to the Initilize stage, which I assume is because it needs the GraphicsDeviceManager to get the window handle to create the GraphicsDevice before it can be exposed for anything to use...

So because of this they cannot be injected into the game because it needs to do its stuff first, and I cannot really push them in after the game is made, because I need other things like the World component to be injected with things as well and pushed into the game.

At this point I thought maybe I could create my own GraphicsDevice, but as I need the handle I would need to make my own window too, which I later realised XNA would dispose and recreate anyway. So it leaves me with a horrible taste in my mouth... as I dont fancy re-writing the Game and GraphicsDeviceManager classes, which would require me to re-write lots of other functionality as they are all internal to the XNA assembly...

So has anyone managed to setup their dependency injection without having to re-write large chunks of XNA?

Here is an example of my current module:

public class XnaModule : NinjectModule
{
    public override void Load()
    {
        Kernel.Bind<IServiceProvider>().To<NinjectServiceProvider>().InSingletonScope();
        Kernel.Bind<IGraphicsDeviceService>().To<GraphicsDeviceManager>().InSingletonScope();
        Kernel.Bind<ContentManager>().ToSelf().InSingletonScope();
        Kernel.Bind<SpriteBatch>().ToSelf().InSingletonScope();

        var contentManager = new ContentManager(Kernel.Get<IServiceProvider>());
        contentManager.RootDirectory = "Content";
        Kernel.Bind<ContentManager>().ToConstant(contentManager).InSingletonScope();

        var game = new MyGame(Kernel.Get<IGraphicsDeviceService>() as GraphicsDeviceManager,
                                    Kernel.Get<SpriteBatch>(), contentManager);
        Kernel.Bind<Game>().ToConstant(game).InSingletonScope();
    }
}

Then the game constructor:

public class MyGame : Game
{
    public SpriteBatch SpriteBatch { get; private set; }
    public GraphicsDeviceManager Graphics { get; private set; }

    public MyGame(GraphicsDeviceManager graphics, SpriteBatch spriteBatch, ContentManager contentManager)
    {
        Graphics = graphics;
        SpriteBatch = spriteBatch;
        Content = contentManager;
    }

    // Other stuffs
}

Both are just examples so you can see the sort of approach I am taking, the module bypasses the circular dependency issue as I new the game up myself. And I have excluded the GameModule, which would contain the dependencies for my actual Game objects, i.e factories, gui components etc, and the problem is they ultimately need to be injected into the Game too, and we then we have a catch22.

As they cannot be injected until the dependencies are resolved, but you cannot resolve the dependencies until you have started the game... it seems a lose/lose situation. So can anyone tell me how they got round this issue?

I did find http://steveproxna01di.codeplex.com/ but was looking if there are any more examples as this is more of a service locator approach, rather than an Injection approach.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浮萍、无处依 2025-01-04 04:37:35

由于没有人回答这个问题,我将补充说,我基本上将我的 Game 实例变成了自定义 IGame 实例的包装器和引导程序,该实例是根注入点。这样我就可以注入任何我想要的东西。

As no one has answered this, I will put in that I basically turned my Game instance into a wrapper and bootstrapper for a custom IGame instance which is the root injection point. This way I am able to inject whatever I want.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文