Click here to Skip to main content
15,881,248 members
Articles / Programming Languages / C#

Dependency Injected Singletons… What?

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
2 Aug 2013CPOL4 min read 31.5K   4   9   6
About dependency injected singletons

Background

Previously, I wrote a bit about singletons. I’m not afraid to say that I think singletons have a time and a place… Okay, I’m afraid to say it, but it’s actually how I feel. :) After learning more and more about inversion of control design patterns and programming by interfaces, I started to notice just how inflexible singletons are. Here’s an example of my approach for mixing singletons, programming by interfaces, and a bit of inversion of control.

The Setup

I’m actually surprised you got this far. I’m sure you’re probably just sticking around to see how messed up this could possibly be. I’m actually proud that this little pattern has worked out so well when I’ve used it, so it can’t possibly be that bad. 

One major drawback to singletons is that they are often implemented as concrete classes. That is, you ask some class X for its instance (via a static property/method) and it provides you with it. This doesn’t mix very well with programming by interfaces. So, the first step is to have your singleton return an interface instead of a concrete class. Unfortunately, this on its own only provides a few benefits, and it’s really only a minor abstraction layer. You can change your singleton class around all you want, but the only dependencies people are going to see are what’s exposed on the interface. As long as your interface isn’t changing, you’re in a good position. With this change alone, we’ve managed to tackle a bit on programming by interfaces, which makes me just a bit happier.

So, what’s the problem now then? Well, now that I have my singleton returning an interface, the unfortunate truth is that it’s always going to be the same class backing that interface. It’s incredibly risky if I start putting some sort of logic in my singleton’s property to get the instance that will return different references that could implement the interface. I mean, once your code is running, you want to make sure you’re always getting the same reference back… or else you’re not using a singleton! The drawback to this is that it completely ruins inversion of control and dependency injection! 

An Example

Consider that I have a singleton that has information about my application. (If you don’t like my example, then you’ll surely hate using WinForms, because Microsoft does it with their Application class. So, it’s a fair example!) Okay, so if we pretend that we need something just like the Application class in our project, we might create some interface IApplication and create a singleton that returns an instance of an IApplication.

Suppose in one implementation we have, we really want to be using reflection and the assembly information to figure out our application’s information. Our concrete class would implement the IApplication interface but the methods would revolve around using reflection and querying the assembly for what it wants. If we built up a whole framework that used this singleton… We’d be tied to that implementation!

What happens if we go to make another application that wants to use this same framework, but it needs to be able to provide the application information through a configuration file? Well… we’d be pooched! Our singleton that’s used everywhere (and yes, please continue crying about the use of the singleton… Just remember Microsoft’s Application class) and we can’t really do anything about it!

Or can we?

The “Solution”

Okay, so here we are. I’ve demonstrated the problem with a scenario that isn’t too far fetched. How do we fix this crappy situation we’ve got ourselves in by using the dreaded singleton pattern? We use my other best friend: events. Except we use them in a way that makes me cringe. Static events.

Here’s my solution to the above problem:

The Interface

C#
public interface IApplication
{
    string Name { get; }

    string Version { get; }
}

The Singleton

C#
public static class Application
{
    private static readonly object _instanceLock = new object();
    private static IApplication _instance;

    public static event EventHandler<QueryTypeEventArgs> QueryType;

    public static IApplication Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_instanceLock)
                {
                    if (_instance == null)
                    {
                        _instance = CreateInstance();
                    }
                }
            }

            return _instance;
        }
    }

    private static IApplication CreateInstance()
    {
        var handler = QueryType;
        if (handler == null)
        {
            throw new InvalidOperationException(
                "Cannot create an instance because the QueryType event " +
                "handler was never set.");
        }

        var args = new QueryTypeEventArgs();
        handler.Invoke(null, args);

        if (args.Type == null)
        {
            throw new InvalidOperationException(
                "Cannot create an instance because the type has not been " +
                "provided.");
        }

        // NOTE: Here's where things get weird. you need to define your own
        // sort of "contract" for what type of constructor you will allow.
        // you might not even use a constructor here... but you need to
        // define what mechanism the provided type must have to provide
        // you with a singleton instance. i'm a fan of providing a type
        // with a private parameterless constructor, so I'll demonstrate
        // with that. your requirements will change what this section of
        // code looks like.
        if (!typeof(IApplication).IsAssignableFrom(args.Type))
        {
            throw new InvalidOperationException(
                "Cannot create an instance because the provided type does " +
                "not implement the IApplication interface.");
        }

        const BindingFlags FLAGS =
            BindingFlags.CreateInstance |
            BindingFlags.Instance |
            BindingFlags.NonPublic;

        var constructors = args.Type.GetConstructors(FLAGS);
        if (constructors.Length != 1)
        {
            throw new InvalidOperationException(
                "Cannot create an instance because a single private " +
                "parameterless constructor was expected.");
        }

        return (IApplication)constructors[0].Invoke(null);
    }
}

The Program (With two types to inject!)

C#
internal class Program
{
    private static void Main(string[] args)
    {
        Application.QueryType += (sender, e) =>
        {
            e.Type = typeof(ApplicationB);
        };

        Console.WriteLine(string.Format(
            "Application Name: {0}\r\nVersion: {1}",
            Application.Instance.Name,
            Application.Instance.Version));

        Console.WriteLine("Press enter to exit.");
        Console.ReadLine();
    }
}

internal class ApplicationA : IApplication
{
    private ApplicationA()
    {
    }

    public string Name
    {
        get
        {
            return "Application A (Pretend this was from the assembly info)";
        }
    }

    public string Version
    {
        get { return "1234"; }
    }
}

internal class ApplicationB : IApplication
{
    private ApplicationB()
    {
    }

    public string Name
    {
        get
        {
            return "Application B (Pretend this was from an XML file)";
        }
    }

    public string Version
    {
        get { return "9876"; }
    }
}

So, if you were to run the program, what outputs would you expect in either case? What happens when you forget to set your event handler? What happens when you set your event handler and don’t provide a type? What if it’s a bad type?

Summary

I’m not claiming that this is the best approach to solve this problem, and I’m not even encouraging that everyone go ahead and use it. Some of the pros of this are:

  • Advantages of programming by interfaces! You’re only exposing interface definitions to others
  • Dependency injection capabilities. Inject your “singleton” into other applications
  • All the goodies related to singletons
  • Easy to use. Just hook up your type to a event handler when your program initializes.

Some of the cons are:

  • All the things people hate about singletons. All of them.
  • Static events are absolutely hideous.
  • You’re giving some other class control of creating your singleton instance.
  • There is no compile time checking or contracts for how your singleton needs to be created.

And now that you know some of the good and some of the bad, can you leverage a design like this? You can check out a working solution I put together for the code and example I described above over at Google Code. Hope you were able to learn something (either good or bad)!

The post Dependency Injected Singletons… What? appeared first on Nick's Blog.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader Microsoft
United States United States
I'm a software engineering professional with a decade of hands-on experience creating software and managing engineering teams. I graduated from the University of Waterloo in Honours Computer Engineering in 2012.

I started blogging at http://www.devleader.ca in order to share my experiences about leadership (especially in a startup environment) and development experience. Since then, I have been trying to create content on various platforms to be able to share information about programming and engineering leadership.

My Social:
YouTube: https://youtube.com/@DevLeader
TikTok: https://www.tiktok.com/@devleader
Blog: http://www.devleader.ca/
GitHub: https://github.com/ncosentino/
Twitch: https://www.twitch.tv/ncosentino
Twitter: https://twitter.com/DevLeaderCa
Facebook: https://www.facebook.com/DevLeaderCa
Instagram:
https://www.instagram.com/dev.leader
LinkedIn: https://www.linkedin.com/in/nickcosentino

Comments and Discussions

 
QuestionQueryTypeEventArgs cannot be found Pin
Member 1419417528-May-21 7:03
Member 1419417528-May-21 7:03 
QuestionYou've got my 5 ! Pin
Erlend Robaye24-Apr-14 21:26
Erlend Robaye24-Apr-14 21:26 
AnswerRe: You've got my 5 ! Pin
Dev Leader25-Apr-14 1:57
Dev Leader25-Apr-14 1:57 
QuestionOne issue Pin
dfvdf56757567555-Aug-13 4:08
dfvdf56757567555-Aug-13 4:08 
AnswerRe: One issue Pin
Dev Leader5-Aug-13 4:15
Dev Leader5-Aug-13 4:15 
GeneralRe: One issue Pin
dfvdf567575675514-Aug-13 1:13
dfvdf567575675514-Aug-13 1:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.