Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Factory Creating Objects According to a Generic Type C#

What would be the most efficient way to instanciate an object according to a generic type passed to a Factory class, for instance:

public class LoggerFactory
{
    public static ILogger<T> Create<T>()
    {
        // Switch Statement?
        // Generic Dictionary?
        // EX.: if "T" is of type "string": return (ILogger<T>)new StringLogger();
    }
}

How would you do it? Which branching statement? etc...

like image 970
maxbeaudoin Avatar asked Jul 17 '09 18:07

maxbeaudoin


1 Answers

I think it's best to keep it simple, perhaps something like this:

public static class LoggerFactory
{
    static readonly Dictionary<Type, Type> loggers = new Dictionary<Type, Type>();

    public static void AddLoggerProvider<T, TLogger>() where TLogger : ILogger<T>, new()
    {
        loggers.Add(typeof(T), typeof(TLogger));
    }

    public static ILogger<T> CreateLogger<T>()
    {
        //implement some error checking here
        Type tLogger = loggers[typeof(T)];

        ILogger<T> logger = (ILogger<T>) Activator.CreateInstance(tLogger);

        return logger;
    }
}

You just call the AddLoggerProvider for each type you want to support, can be extended at runtime, it ensures you definetly add an implementation of the interface to the library and not some object, isn't very fast because of the Activator, but creating a logger wont likely be a bottleneck anyway. Hope it looks okay.

Usage:

// initialize somewhere
LoggerFactory.AddLoggerProvider<String, StringLogger>();
LoggerFactory.AddLoggerProvider<Exception, ExceptionLogger>();
// etc..

ILogger<string> stringLogger = LoggerFactory.CreateLogger<string>();

Note: each ILogger<T> requires a parameterless constructor for the Activator, but that too is ensured with the new() generic constraint in the add method.

like image 105
Kenan E. K. Avatar answered Oct 06 '22 00:10

Kenan E. K.