Factory Class Generator
Generate a GoF-style factory class from an abstract base or interface using [FactoryClass] on the base and [FactoryClassKey] on concrete implementations.
Quick start
using PatternKit.Generators.Factories;
namespace Demo;
[FactoryClass(typeof(string), FactoryTypeName = "NotificationFactory")]
public interface INotification { }
[FactoryClassKey("email")]
public class Email : INotification { }
[FactoryClassKey("sms")]
public class Sms : INotification { }
Generated factory (sync):
public sealed partial class NotificationFactory
{
public INotification Create(string key);
public bool TryCreate(string key, out INotification result); // unless GenerateTryCreate = false
}
Async is generated when any product exposes public static CreateAsync() returning Task<TBase> or ValueTask<TBase>:
public ValueTask<INotification> CreateAsync(string key);
public ValueTask<(bool Success, INotification Result)> TryCreateAsync(string key);
Enum keys
Set GenerateEnumKeys = true to emit:
- Nested
enum Keyscontaining all registered keys (sanitized identifiers). - Overloads of
Create/TryCreate/CreateAsync/TryCreateAsyncthat accept the enum.
Behavior
- Base requirement —
[FactoryClass]must decorate an interface or abstract class. - Product discovery —
[FactoryClassKey]types must be concrete and implement/derive exactly one[FactoryClass]base. - Construction — Uses public parameterless ctor when present; otherwise looks for
static CreateAsync()on the product. Async factories are awaited; sync products are wrapped inValueTask.FromResultfor async APIs. - Key handling — Keys must convert implicitly to
KeyType. Duplicate keys per base are rejected. - Defaults — No default branch; unknown keys throw in
Createand returnfalseinTryCreate.
Diagnostics
| Id | Message | Fix |
|---|---|---|
| PKCF001 | [FactoryClass] must be interface or abstract class |
Mark the base interface or abstract class. |
| PKCF002 | [FactoryClassKey] type maps to multiple bases |
Ensure each product implements only one [FactoryClass] base. |
| PKCF003 | [FactoryClassKey] type must be concrete |
Remove abstract and supply an accessible ctor. |
| PKCF004 | Duplicate factory key | Remove duplicate keys per base type. |
| PKCF005 | Invalid factory key value | Ensure the key literal converts implicitly to KeyType. |
| PKCF006 | Missing accessible constructor | Add public parameterless ctor or static CreateAsync() returning Task/ValueTask<TBase>. |
Tips
- Use
FactoryTypeNameto control the emitted factory name; otherwise{BaseName}Factoryis used. - When you need enum-friendly calling code (e.g., switches), enable
GenerateEnumKeysfor typed overloads. - Prefer
ValueTask<TBase>forCreateAsyncon products;Task<TBase>is wrapped when present.