views:

210

answers:

1

How do I handle classes with static methods with Ninject?

That is, in C# one can not have static methods in an interface, and Ninject works on the basis of using interfaces?

My use case is a class that I would like it to have a static method to create an unpopulated instance of itself.

EDIT 1

Just to add an example in the TopologyImp class, in the GetRootNodes() method, how would I create some iNode classes to return? Would I construct these with normal code practice or would I somehow use Ninject? But if I use the container to create then haven't I given this library knowledge of the IOC then?

public interface ITopology
{
    List<INode> GetRootNodes();
}


public class TopologyImp : ITopology
{
    public List<INode> GetRootNodes()
    {
        List<INode> result = new List<INode>();

        // Need code here to create some instances, but how to without knowledge of the container?
        // e.g. want to create a few INode instances and add them to the list and then return the list 
    }
}

public interface INode
{
    // Parameters
    long Id { get; set; }
    string Name { get; set; }
}

class NodeImp : INode
{
    public long Id
    {
        get { throw new NotImplementedException(); }
        set { throw new NotImplementedException(); }
    }

    public string Name
    {
        get { throw new NotImplementedException(); }
        set { throw new NotImplementedException(); }
    }
}


// Just background to highlight the fact I'm using Ninject fine to inject ITopology
public partial class Form1 : Form
{
    private ITopology _top;
    public Form1()
    {
        IKernel kernal = new StandardKernel(new TopologyModule());
        _top = kernal.Get<ITopology>();
        InitializeComponent();
    }
}
+2  A: 

If you're building a singleton or something of that nature and trying to inject dependencies, typically you instead write your code as a normal class, without trying to put in lots of (probably incorrect) code managing the singleton and instead register the object InSingletonScope (v2 - you didnt mention your Ninject version). Each time you do that, you have one less class that doesnt surface its dependencies.

If you're feeling especially bloody-minded and are certain that you want to go against that general flow, the main tools Ninject gives you is Kernel.Inject, which one can use after you (or someone else) has newd up an instance to inject the dependencies. But then to locate one's Kernelm you're typically going to be using a Service Locator, which is likely to cause as much of a mess as it is likely to solve.

EDIT: Thanks for following up - I see what you're after. Here's a hacky way to approximate the autofac automatic factory mechanism :-

/// <summary>
/// Ugly example of a not-very-automatic factory in Ninject
/// </summary>
class AutomaticFactoriesInNinject
{
    class Node
    {
    }

    class NodeFactory
    {
        public NodeFactory( Func<Node> createNode )
        {
            _createNode = createNode;
        }

        Func<Node> _createNode;
        public Node GenerateTree()
        {
            return _createNode();
        }
    }

    internal class Module : NinjectModule
    {
        public override void Load()
        {
            Bind<Func<Node>>().ToMethod( context => () => Kernel.Get<Node>() );
        }
    }

    [Fact]
    public void CanGenerate()
    {
        var kernel = new StandardKernel( new Module() );
        var result = kernel.Get<NodeFactory>().GenerateTree();
        Assert.IsType<Node>( result );
    }
}

The ToMethod stuff is a specific application of the ToProvider pattern -- here's how you'd do the same thing via that route:-

    ...

    class NodeProvider : IProvider
    {
        public Type Type
        {
            get { return typeof(Node); }
        }
        public object Create( IContext context )
        {
            return context.Kernel.Get<Node>();
        }
    }

    internal class Module : NinjectModule
    {
        public override void Load()
        {
            Bind<Func<Node>>().ToProvider<NodeProvider>();
        }
    }

    ...

I have not thought this through though and am not recommending this as A Good Idea - there may be far better ways of structuring something like this. @Mark Seemann? :P

I believe Unity and MEF also support things in this direction (keywords: automatic factory, Func)

EDIT 2: Shorter syntax if you're willing to use container-specific attributes and drop to property injection (even if Ninject allows you to override the specific attributes, I much prefer constructor injection):

    class NodeFactory
    {
        [Inject]
        public Func<Node> NodeFactory { private get; set; }
        public Node GenerateTree()
        {
            return NodeFactory();
        }
    }
Ruben Bartelink
Hi Ruben - I've added some clarification to the question. How would you create the INode instances yourself in this case? (i.e. see this point in the code which I've commented) - thanks
Greg
@Greg: This any good?
Ruben Bartelink
Thanks Ruben- I'll have to let this sink in. I'm kind of pondering what tangible benefits this approach would really have over just creating the classes normally at the spot I indicated in my code? Do you see one? Like would it really break the IOC concept noting in all other areas of your code you did follow the Ninject approach?
Greg
PS Is it true to say that Ninject doesn't support this, however some other IOC containers do? (just say mention of autofaq in the response above) - thanks
Greg
From my quick trawl around, it seems that autofac supports it natively. Unity also supports it but I didnt look at how. MEF supports it but it's not primarily a DI container (and it probably won't be easy to use it without attributes). Didnt see mention of any others. Also while OOTB there isnt a way in Ninject, there may be an extension, and you'll get a more conclusive answer from the committers on http://groups.google.com/group/ninject (or maybe @Ian Davis is listening in here?)
Ruben Bartelink
I think the solution I posted is definitely worth using over raw `new` s as 1) You're keeping the specific bindings outside the class 2) you're not having to deal with the mess and confusion that using a Service Locator (i.e., some global place that you go and ask for dependencies) would impose and 3) you can code in the same consistent manner (without inconsistencies in style of dependency management messing your code) throughout. i.e., If you dont externalise the concern in this manner, you'll end up doing `GlobalKernel.Get<T>()` or a `new` followed by a `GlobalKernel.Inject( newed)`
Ruben Bartelink
Having said that... if you're just managing simple value types and it's possible to isolate the tree stuff in its own area then there's no prohibition on using good old `new`! - and if you take care with it, the code may end up simpler. Use your judgement and you'll be fine.
Ruben Bartelink
I also added a shorter syntax that may float your boat (though I stopped using prop injection (and container-specific attributes) a long time ago. (But I sense that it's the cleanliness and appropriateness more than the length of the code that's bothering you)
Ruben Bartelink