views:

188

answers:

3

I have a class with a public constructor:

    public MasterEngine(IInputReader inputReader)
    {
        this.inputReader = inputReader;

        graphicsDeviceManager = new GraphicsDeviceManager(this);
        Components.Add(new GamerServicesComponent(this));
    }

How can I inject dependencies like graphicsDeviceManager and new GamerServicesComponent while still supplying the argument this?

+1  A: 

This blog suggests one method of providing GameServices which in turn allow things like the GraphicsDeviceManager to be injected. I have recently implemented a project using an approach similiar to this and it worked a treat.

Finglas
I should mention the this parameter refers to the Game instance. All the constructor really should care for is the GameService container but unfortunately the default way of using XNA is not IOC friendly. It's certainly possible, you just have to do things the correct OO way, not the XNA way.
Finglas
That demo is nice, but it's for Ninject 1, not 2.
Rosarch
I've done it with version 2. What part exactly is causing problems?
Finglas
+1  A: 

You should be able to inject factory delegates for the components instead of the actual components. NInject supports binding delegates out-of-the-box via its Bind<>().ToMethod().

The nice thing about such a construct is that you get the benefits of constructor injection while at the same time enables the instance (MasterEngine in this case) to control when dependencies are instantiated.

Your constructor should look something like this:

public MasterEngine(IInputReader inputReader, 
    Func<MasterEngine,GraphicsDeviceManager> graphicsDeviceFactory,
    Func<MasterEngine,GamerServicesComponent> gamerServicesFactory)
{
    this.inputReader = inputReader;

    graphicsDeviceManager = graphicsDeviceFactory(this);
    Components.Add(gamerServicesFactory(this));
}

Here's how you bind the factory delegates, which imo is a tidier way:

Bind<Func<MasterEngine, GraphicsDeviceManager>>()
   .ToMethod(context => engine => new GraphicsDeviceManager(engine));
Bind<Func<MasterEngine, GamerServicesComponent>>()
   .ToMethod(context => engine => new GamerServicesComponent(engine));

This can also be done with delegate types:

public delegate GraphicsDeviceManager GdmFactory(MasterEngine engine); 
public delegate GamerServicesComponent GscFactory(MasterEngine engine); 

...

Bind<GdmFactory>()
   .ToMethod(context => engine => new GraphicsDeviceManager(engine));
Bind<GscFactory>()
   .ToMethod(context => engine => new GamerServicesComponent(engine));

...

public MasterEngine(IInputReader inputReader, 
    GdmFactory graphicsDeviceFactory,
    GscFactory gamerServicesFactory)
{
    ...
}
Peter Lillevold
What would the Ninject code for this look like? I'm still not sure how those arguments would be supplied.
Rosarch
@Rosarch after trying out ninject I figured out how to register delegates. Hope it helps!
Peter Lillevold
To those who downvoted: I'm all for downvotes when they are accompanied by constructive criticism. Otherwise, I cannot see that my answer is either wrong or inappropriate.
Peter Lillevold
Yeah I have no idea what the downvote was for. Some random griefer?
Rosarch
Hm, probably. Imagine that... I have enemies on SO! :)
Peter Lillevold
A: 
kernel.Bind<IInputReader>()
                    .To<SomeInputReader>()
                    .OnActivation(instance =>
                                    {
                                        instance.GraphicsDeviceManager = new GraphicsDeviceManager(instance);
                                        Components.Add(new GamerServicesComponent(instance));
                                    });
Ian Davis
...just wanted to point out: this approach breaks encapsulation. I wouldn't want to expose internals just to make injection work. Property injection should imo only be used when dependencies are optional.
Peter Lillevold
I have no idea what is internal for the XNA objects. Not knowing how XNA works, it seems like his objects are too tightly bound together. I am really not a fan of circular dependencies.
Ian Davis