0

Given this code:

using System;
using System.Collections.Generic;
using FactoryCallback = System.Func<System.Object>;

interface IMessageProvider
{
    string Message { get; }
}

class MessageProvider : IMessageProvider
{
    private Random generator = new Random();

    public static void Register()
    {
        InstanceFactory.Register(typeof(IMessageProvider), () => new MessageProvider());
    }

    public string Message
    {
        get
        {
            switch (generator.Next(3))
            {
                case 0:
                    return "No matter where you go, there you are.";
                case 1:
                    return "Once I thought I'd made a mistake, but I was wrong.";
                case 2:
                    return "I used to think I was indecisive; now I'm not so sure";
                default:
                    throw new IndexOutOfRangeException();
            }
        }
    }
}

class InstanceFactory
{
    private static Dictionary<Type, FactoryCallback> typeCallbacks =
        new Dictionary<Type, FactoryCallback>();

    public static void Register(Type type, FactoryCallback callback)
    {
        typeCallbacks.Add(type, callback);
    }

    public static Object InstanceOf(Type type)
    {
        return typeCallbacks[type]();
    }
}

public class RandomMessage
{
    public static void Main()
    {
        IMessageProvider provider =
            InstanceFactory.InstanceOf(typeof(IMessageProvider)) as IMessageProvider;
        Console.WriteLine(String.Format("The message is:\n{0}", provider.Message));
    }
}

This program will not run successfully as is because the MessageProvider never actually registers with the InstanceFactory. Obviously, a call to MessageProvider.Register could be added to the beginning of RandomMessage.Main. However, that now requires RandomMessage to have knowledge of MessageProvider and defeats the whole purpose of the InstanceFactory class which is intended to separate how to create something from what that something does. I would like the MessageProvider to be able to automatically register with the InstanceFactory before RandomMessage.Main tries to create an IMessageProvider instance. How could this be accomplished?

Tron Thomas
  • 871
  • 7
  • 20

3 Answers3

3

The registration of service IMessageProvider and component MessageProvider with InstanceFactory is not the responsbility of the MessageProvider implementation, it is an infrastructure concern for the application, therefore should be done inside of the Main method.

public class RandomMessage
{
    public static void Main()
    {
        // Register services with InstanceFactory at the start of Main method
        InstanceFactory.Register(typeof(IMessageProvider), () => new MessageProvider());

        IMessageProvider provider = InstanceFactory.InstanceOf(typeof(IMessageProvider)) as IMessageProvider;
        Console.WriteLine(String.Format("The message is:\n{0}", provider.Message));
    }
}
Russ Cam
  • 124,184
  • 33
  • 204
  • 266
0

If you somehow referenced MessageProvider before calling InstanceFactory.InstanceOf(), you could just add a static constructor to MessageProvider class:

static MessageProvider()
{
    Register();
}

If it's not an option, you can do it via reflection by adding a custom attribute to all classes you want to register and calling Register() for all of them in static constructor of InstanceFactory like described here.

Community
  • 1
  • 1
Anton Savin
  • 40,838
  • 8
  • 54
  • 90
  • If you never reference the `MessageProvider` class in the execution flow, either with a static method or by instantiating it, the static constructor will never be called. – greenboxal Sep 21 '14 at 23:58
0

Consider using some Inversion of Control library. like Unity (but it might be overkill) or SimpleContainer.

Then you will 'Register' instance of interfaces while your app start (in examples you should have file like 'bootstrapper.cs' )

nilphilus
  • 590
  • 1
  • 5
  • 23