When using Dependency Injection (DI) containers, you often need to create new instances of objects at runtime—not just at startup. However, doing this directly with the container in your application code defeats the whole purpose of DI: keeping your code decoupled from the container.
The typical solution is to use factories: wrapper classes that handle the complexity of creating instances while keeping the container logic isolated. Unfortunately, writing factories is tedious boilerplate code that gets repeated across your codebase.
AutoFactories automatically generates factory classes for you during compilation. Just add a single attribute to your class, and you get a fully-typed factory with all the boilerplate written for you—automatically.
This code below uses this library to auto generate the IShippingOrderFactory and its Get method. Just add [AutoFactory] to your class, and the factory is generated automatically. Parameters marked with [FromFactory] come from your DI container, while others become factory method arguments.
namespace Operations
{
[AutoFactory]
public class ShippingOrder
{
public ShippingOrder(
string orderId,
[FromFactory] IShippingProvider provider)
{}
}
public class Program
{
public static void Main(string[] args)
{
IShippingProvider provider = new ShippingProvider();
// The factory is auto-generated with a constructor for DI dependencies
IShippingOrderFactory factory = new ShippingOrderFactory(provider);
// The Create method only takes user-provided parameters
ShippingOrder shippingOrder = factory.Create(orderId:"A2123F")
}
}
}AutoFactories works seamlessly with popular DI containers:
public static void Main(string[] args)
{
IKernel kernel = new StandardKernel()
.AddAutoFactories(); // Registers all generated factories
IShippingOrderFactory factory = kernel.Get<IShippingOrderFactory>();
ShippingOrder shippingOrder = factory.Create(orderId:"A2123F")
}using Microsoft.Extensions.DependencyInjection;
public static void Main(string[] args)
{
IServiceProvider serviceProvider = new ServiceCollection()
.AddAutoFactories() // Registers all generated factories
.BuildServiceProvider();
IShippingOrderFactory factory = serviceProvider.GetRequiredService<IShippingOrderFactory>();
ShippingOrder shippingOrder = factory.Create(orderId:"A2123F")
}When you apply [AutoFactory] to a class, AutoFactories generates:
- A Factory Class - contains the factory methods
- A Factory Interface - for dependency injection
- Create Methods - one for each constructor in your class
Parameters marked with [FromFactory] are automatically resolved by the container. All other parameters become method arguments, with compile-time type safety (no more magic string parameter names).
This class:
[AutoFactory]
public class Coffee
{
public Size Size { get; }
public IMilkService Milk { get; }
public Coffee(
Size size,
[FromFactory] IMilkService milkService)
{}
}Generates this factory (simplified):
public interface ICoffeeFactory
{
Coffee Create(Size size);
}
internal partial class CoffeeFactory : ICoffeeFactory
{
private readonly IResolutionRoot m_resolutionRoot;
public CoffeeFactory(IResolutionRoot resolutionRoot)
{
m_resolutionRoot = resolutionRoot;
}
public Coffee Create(Size size)
{
return m_resolutionRoot.Get<Coffee>(
new ConstructorParameter(nameof(size), size));
}
}Notice: the parameter name is derived from your source code, so if someone refactors size to coffeeSize, you get a compile-time error—not a runtime crash.
Without factories, you have two bad choices:
- Reference the container everywhere - Your business logic becomes tightly coupled to the DI framework
- Manually write factories - Lots of repetitive boilerplate that's easy to get wrong
AutoFactories solves both problems by generating type-safe factories automatically.
The [AutoFactory] attribute is highly configurable, giving you control over how factories are generated:
[AutoFactory]
public class Coffee { }Generates a factory class named CoffeeFactory with an interface ICoffeeFactory and a method named Create().
Specify the name of the factory method:
[AutoFactory]
public class Coffee { }
[AutoFactory]
public class Espresso { }
public partial class BeverageFactory { }
[AutoFactory(typeof(BeverageFactory), "MakeCoffee")]
public class Coffee { }
[AutoFactory(typeof(BeverageFactory), "MakeEspresso")]
public class Espresso { }This generates both MakeCoffee() and MakeEspresso() methods in a single BeverageFactory class, eliminating naming collisions.
Combine multiple types into one factory:
public partial class AnimalFactory { }
[AutoFactory(typeof(AnimalFactory), "CreateCat")]
public class Cat
{
public Cat(string name, [FromFactory] IVeterinarian vet) { }
}
[AutoFactory(typeof(AnimalFactory), "CreateDog")]
public class Dog
{
public Dog(string breed, [FromFactory] IVeterinarian vet) { }
}Generates:
public partial class AnimalFactory : IAnimalFactory
{
private readonly IVeterinarian m_vet;
public AnimalFactory(IVeterinarian vet) => m_vet = vet;
public Cat CreateCat(string name) => new Cat(name, m_vet);
public Dog CreateDog(string breed) => new Dog(breed, m_vet);
}Change the return type of the generated factory method using ExposeAs:
public interface IClock
{
int Ticks { get; }
}
[AutoFactory(ExposeAs=typeof(IClock))]
public class Clock : IClock
{
public int Ticks { get; }
public Clock(int ticks)
{
Ticks = ticks;
}
}Generates:
public interface IClockFactory
{
// Returns the interface, not the concrete type
IClock Create(int ticks);
}AutoFactories is a Source Generator that generates factory code during compilation. The generated code is:
- Type-safe - Full IntelliSense and compile-time checking
- Zero-overhead - No reflection or runtime costs
- Standard C# - Works with any C# 9+ project
AutoFactories provides special integrations for:
- Generic factories - No framework dependencies
- Ninject - Full integration with Ninject's kernel
- Microsoft.DependencyInjection - Works with ASP.NET Core and other frameworks
Don't see your framework? Open a feature request.