Factory Pattern in .NET - super easy with H.Necessaire

How to easily do factory pattern in .NET using H.Necessaire.

Factory Pattern in .NET - super easy with H.Necessaire
ID and Alias attributes; factory identity markers.

Context

Let's say we want to develop a test data generator for some primitive types.

We start by modelling the abstraction of such a generator.

public interface ImADataGenerator
{
    string GenerateNewValue();
}

Then the abstraction of the factory.

public interface ImADataGeneratorFactory
{
    ImADataGenerator GetGeneratorFor(Type primitiveType);
}

Then the testing runtime.

class Program
{
    public int Main(string[] args)
    {
        ImADataGeneratorFactory dataGeneratorFactory; //Will instantiate once we have the concrete implementation
        
        string intValue = dataGeneratorFactory.GetGeneratorFor(typeof(int)).GenerateNewValue();
        
        string boolValue = dataGeneratorFactory.GetGeneratorFor(typeof(bool)).GenerateNewValue();
        
        string doubleValue = dataGeneratorFactory.GetGeneratorFor(typeof(double)).GenerateNewValue();
        
        string stringValue = dataGeneratorFactory.GetGeneratorFor(typeof(string)).GenerateNewValue();
    }
}

The magic - concrete implementation

The concrete factory

class DataGeneratorFactory : ImADataGeneratorFactory
{
    public ImADataGenerator GetGeneratorFor(Type primitiveType)
    {
        Type type = typeof(ImADataGenerator).GetAllImplementations().FirstOrDefault(x => x.IsMatch(primitiveType.Name));
        
        if(type is null)
            return null;
        
        return (Activator.CreateInstance(type) as ImADataGenerator);
    }
}

The concrete generators

class Int32DataGenerator : ImADataGenerator
{
    public string GenerateNewValue() => 17;
}

class StringDataGenerator : ImADataGenerator
{
    public string GenerateNewValue() => Guid.NewGuid().ToString();
}

///And so on...

That's it. Easy. 💖

As you can see, the factory identifies the concrete implementation based on the type name. The starting part of it to be more specific.

The match is case-insensitive.

If the type name doesn't match, the IsMatch() extension method tries to find the concrete implementation via two more attributes from H.Necessaire:

Furthermore, if you're using the DI framework of H.Necessaire, things get even easier:

ImADependencyProvider dependencyProvider;
ImAnAbstractType concrete = dependencyProvider.Build<ImAnAbstractType>(concreteID);

Visit: H.Necessaire