Generic Factory In C#
The common base class problem
In one of my projects, I have a class hierarchy sharing a common base class - Action<string>.
For simplicity, we’ll name it FileAction in the diagram below.
Multiple classes inherit and extend the base class:

There are more classes in the hierarchy. Additionally, any app using the class hierarchy can add their own Action implementation as needed.
I want to automate the creation of derived classes instances’, based on string identifier.
Also, I want any app using the class hierarchy to use the solution out of the box.
Something like
Action = Solution.Create (“ActionCopyFile”);
So, what’s the solution?
It’s a design pattern named The Factory Method.
Declaring A Generic C# Factory
The GenericFactory class will have:
- one generic argument TBase (the base class of the hierarchy)
- a dictionary to store associations between a string ID and a Creator method (mCreators)
- a register method to associate an ID with a Creator (Register)
- a create method to call the Creator associated with an ID (Create)
This way, we can use the generic factory with multiple class hierarchies.
A Creator is a delegate that will match any method returning a class instance derived from TBase.
We’re also making all class members and methods static.
This way, you won’t have instantiate the factory class every time you want to use it.
The Register Method
Simply adds a new entry to the dictionary.
Some additional checks are required before adding the pair:
- prevent an empty ID
- prevent and empty creator
- prevent duplicate entries
// Registers a creator delegate by id
public static void Register(string id, Creator creator)
{
// TBD: Localize the exception messages
const string KMsgNullId = "ID cannot be null or empty.";
const string KErrDelegateNull = "The creator delegate cannot be null.";
const string KErrCreatorAlreadyRegistered = "There is a creator already registered with ID {0}";
if (string.IsNullOrWhiteSpace(id))
throw new ArgumentException(KMsgNullId, nameof(id));
if (creator == null)
throw new ArgumentNullException(nameof(creator), KErrDelegateNull);
if (!mCreators.TryAdd(id, creator))
throw new InvalidOperationException(string.Format(KErrCreatorAlreadyRegistered, id));
}Using the method looks something like
GenericFactory<string>.Register("actionCopy", () => new ActionCopyFile());I’ve used a lamba expression as the 2nd argument to simply create a new instance of the ActionCopyFile;
But it can be any other method that matches the Creator delegate signature.
The Create Method Call
This method is responsible with finding and invoking the creator associated with and ID.
If no creator was found, an exception is thrown.
// Calls the associated creator for the specified ID
public static TBase Create(string id)
{
if (mCreators.TryGetValue(id, out var creator))
return creator();
throw new KeyNotFoundException($"There is no creator registered with the ID \"{id}\".");
}
Better readability with global usings
If I want to use the generic factory and pass it a generic argument of RealityFrameworks.Actions.Action
RealityFrameworks.GenericFactory<RealityFrameworks.Actions.Action<string> >;There has to be an easier way than this!
Enter global usings.
I’ve created a GlobalUsings.cs file and added it to the project.
Inside it, I’ve put aliases:
// GlobalUsings.cs
global using FileCondition = RealityFrameworks.Conditions.Condition<string>;
global using FileAction = RealityFrameworks.Actions.Action<string>;
global using FileTransform = RealityFrameworks.Transform<string>;
global using FileConditionFactory = RealityFrameworks.GenericFactory<RealityFrameworks.Conditions.Condition<string>>;
global using FileActionFactory = RealityFrameworks.GenericFactory<RealityFrameworks.Actions.Action<string>>;
global using EditorFactory = RealityFrameworks.GenericFactory<CommonForms.EditorBase>;It looks better and much faster to use, don’t you agree?
I’m much happier with the shorthand notation, thank you very much.
The only fallback? The aliases are visible only within the current assembly.
If I want to use those aliases in a different assembly, I must define them again, in their own GlobalUsings.cs file.
Registering multiple creators
In my main app, I’ve created a method to register all creators and calling it once, in the constructor of the main windows form.
private void RegisterCreators()
{
// REGISTER ACTION Creators from RealityFrameworks assembly
FileActionFactory.Register(typeof(ActionCopyFile).Name, () => new ActionCopyFile(Path.GetTempPath()));
FileActionFactory.Register(typeof(ActionAppendToFile).Name, () => new ActionAppendToFile());
FileActionFactory.Register(typeof(ActionRenameFile).Name, () => new ActionRenameFile());
FileActionFactory.Register(typeof(ActionGroup<string>).Name, () => new ActionGroup<string>());
}Using the Create method
And this is how you use the Create method with a generic factory.
string actionId = typeof(ActionCopyFile).Name; // or any other valid action ID
var action = FileActionFactory.Create(actionId);Simply pass a string identifier to the Create method of the factory.
Full Source Code
Download the full generic factory code here.