TinyIOC

As my Mono for Android app continues, I’ve been introducing more and more libraries to try to sort out its structure.

One of the largest changes to my development many moons ago was the use of a dependency injection container. There is only so far that I can go in any project before needing one – even if it’s just a test project.

Greg Shackles wrote about using either TinyIoC or Func with Mono for Android back in Feb 2011.

So I’ve added TinyIoC  to my app and have been registering the classes, adding interfaces to separate component dependencies etc.

Now in WPF / Silverlight, we’ve been spoilt by the powerful AutoFac. It seems a little heavyweight for a phone app though, but that doesn’t stop me wanting some of its power.

I chose to try TinyIoC because:

  • it’s just a single cs file that you include in your project – simples!
  • it had support for automatic factories – so you register T and can then inject Func<T>

What I’ve found that is that many of my components have a mixture of dependencies and parameters in the constructor. AutoFac just copes with this automagically, but I’ve been having to register custom factories for everything in TinyIoC. It’s ok for now but will get tedious quickly. It also uses a slightly cumbersome string object dictionary for custom parameters.

If you’re doing IoC correctly, then none of the components should be affected by which container you’re using – so I might try a different container shortly.

Advertisements

Owned without Owned<> – Part 1

Our neverending quest to make our code neater and tidier continues.

“Given a screen in our application, when the screen closes, make sure everything has been disposed.”

Seems reasonable.

When using a DI container such as Autofac, it seems like a good idea to make the most of its powerful features. If we create the screen is its own child container / lifetime scope, then disposing of that child container disposes the screen and all other objects that it resolved (or that they resolved and so on).

This works very nicely and viewing the app under the memory profiler magnifying glass confirms that everything is being cleared away nicely.

Owned<T>

The syntax for creating the Child Container in AutoFac is by injecting the object you want wrapped (for example the screen) inside an Owned<T>. For more details, see the AutoFac Documentation or Nicholas Blumhardt’s “An Autofac Lifetime Primer”.

Whilst Owned is without doubt powerful and useful, it does has the slight drawback that the fact that an object is Owned can leak out of your component.

So for example, let’s say you are using a strategy pattern to create different Screens, like this:


// Our example Strategies look like this:
public interface IStrategy
{
     IScreen GetScreen();
}

// Here's a strategy that returns Red Screens
public class RedStrategy : IStrategy
{
    private Func<RedScreen> _redScreenFactory;

    // Inject our factory
    public RedStrategy(Func<RedScreen> redScreenFactory)
    {
        _redScreenFactory = redScreenFactory;
    }

    public IScreen GetScreen()
    {
        return _redScreenFactory();
    }
}

You can imagine having several different types of strategies returning, say, Blue and Green screens.

Anyway, let’s say that Red Screens create lots of children and are particularly prone to leaking memory. It would be nice to wrap them in an Owned.

However, what does our strategy return to the consumer?


public class RedStrategy : IStrategy
{
    // Our factory now creates Owned<RedScreen>
    private Func<Owned<RedScreen>> _redScreenFactory;

    // Inject our factory
    public RedStrategy(Func<Owned<RedScreen>> redScreenFactory)
    {
        _redScreenFactory = redScreenFactory;
    }

    public IScreen GetScreen()
    {
        var ownedRedScreen = _redScreenFactory();
        return // ...?
    }
}

If we return ownedRedScreen.Value then we are losing the reference to the child container. This means that we can’t dispose it and clean up all of the contents.

On the other hand, if we change the IStrategy interface to this:

Owned<IScreen> GetScreen()

…then we are forcing all IStrategy implementations to wrap their IScreens in a child container. We are also leaking the fact that they are Owned the consumer and it must now handle Owned<IScreen>.

(This is not to even mention that Owned<RedScreen> can’t be cast to Owned<IScreen> either).

I’ll explain a couple of solutions we came up with – one neat, and one very neat (imho of course :-))