.N .NET Landscape

AutoCtor

Source Generators & Metaprogramming
github.com/distantcam/AutoCtor

A Roslyn source generator for creating constructors.

csharpcsharp-sourcegeneratordotnetroslynsource-generator
GitHub stars
114
Forks
4
Open issues
1
NuGet downloads
274,595
latest 4.0.2
License
MIT
Language
C#
Last push
3 days ago
20 Oct 2026
Created
9 Jul 2022

AutoCtor

NuGet Status Nuget Downloads Build Status GitHub last commit

AutoCtor is a Roslyn Source Generator that will automatically create a constructor for your class for use with constructor Dependency Injection.

+[AutoConstruct]
public partial class AService
{
    private readonly IDataContext _dataContext;
    private readonly IDataService _dataService;
    private readonly IExternalService _externalService;
    private readonly ICacheService _cacheService;
    private readonly ICacheProvider _cacheProvider;
    private readonly IUserService _userService;

-    public AService(
-        IDataContext dataContext,
-        IDataService dataService,
-        IExternalService externalService,
-        ICacheService cacheService,
-        ICacheProvider cacheProvider,
-        IUserService userService
-    )
-    {
-        _dataContext = dataContext;
-        _dataService = dataService;
-        _externalService = externalService;
-        _cacheService = cacheService;
-        _cacheProvider = cacheProvider;
-        _userService = userService;
-    }
}

Contents

NuGet packages

https://nuget.org/packages/AutoCtor/

Code Fixes (new in 3.0)

Starting in version 3.0, a new diagnostic has been introduced: ACTR007 Use [AutoConstruct] instead of manual constructor. This will appear on constructors that can be automatically converted to use [AutoConstruct]. A code fix is also available to perform the conversion automatically.

In 3.1 another code fix was added: Add [AutoConstruct] to type. This will add [AutoConstruct] to a type with no constructor and relevant fields. This is useful when working on a new type.

Service Provider Source Generator (new in 4.0)

In version 4.0 you can now generate your own Service Provider that will work with the constructors generated by AutoCtor. See Service Provider

Examples

Basic

[AutoConstruct]
public partial class Basic
{
    private readonly IService _service;
    private readonly IList<string> _list = new List<string>();
}

snippet source | anchor

What gets generated

//HintName: Basic.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

partial class Basic
{
	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public Basic(global::IService service)
	{
		this._service = service;
	}
}

snippet source | anchor

Inherited

public abstract class BaseClass
{
    protected IAnotherService _anotherService;

    public BaseClass(IAnotherService anotherService)
    {
        _anotherService = anotherService;
    }
}

[AutoConstruct]
public partial class Inherited : BaseClass
{
    private readonly IService _service;
}

snippet source | anchor

What gets generated

//HintName: Inherited.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

partial class Inherited
{
	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public Inherited(
		global::IAnotherService anotherService,
		global::IService service
	) : base(anotherService)
	{
		this._service = service;
	}
}

snippet source | anchor

Properties

// AutoCtor will initialize these
public string GetProperty { get; }
protected string ProtectedProperty { get; }
public string InitProperty { get; init; }
public required string RequiredProperty { get; set; }

// AutoCtor will ignore these
public string InitializerProperty { get; } = "Constant";
public string GetSetProperty { get; set; }
public string FixedProperty => "Constant";
public string RedirectedProperty => InitializerProperty;

snippet source | anchor

What gets generated

//HintName: Properties.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

partial class Properties
{
	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public Properties(
		string getProperty,
		string protectedProperty,
		string initProperty,
		string requiredProperty
	)
	{
		this.GetProperty = getProperty;
		this.ProtectedProperty = protectedProperty;
		this.InitProperty = initProperty;
		this.RequiredProperty = requiredProperty;
	}
}

snippet source | anchor

Back to Contents

Post Constructor Initialization

You can mark a method to be called at the end of the constructor with the attribute [AutoPostConstruct]. This method must return void.

[AutoConstruct]
public partial class PostConstruct
{
    private readonly IService _service;

    [AutoPostConstruct]
    private void Initialize()
    {
    }
}

snippet source | anchor

What gets generated

//HintName: PostConstruct.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

partial class PostConstruct
{
	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public PostConstruct(global::IService service)
	{
		this._service = service;
		Initialize();
	}
}

snippet source | anchor

Extra Parameters

Post construct methods can also take parameters. The generated constructor will include these parameters.

[AutoConstruct]
public partial class PostConstructWithParameter
{
    private readonly IService _service;

    [AutoPostConstruct]
    private void Initialize(IInitializeService initialiseService)
    {
    }
}

snippet source | anchor

What gets generated

//HintName: PostConstructWithParameter.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

partial class PostConstructWithParameter
{
	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public PostConstructWithParameter(
		global::IService service,
		global::IInitializeService initialiseService
	)
	{
		this._service = service;
		Initialize(initialiseService);
	}
}

snippet source | anchor

out/ref Parameters

Parameters marked with out or ref are set back to any fields that match the same type. This can be used to set readonly fields with more complex logic.

[AutoConstruct]
public partial class PostConstructWithOutParameter
{
    private readonly IService _service;
    private readonly IOtherService _otherService;

    [AutoPostConstruct]
    private void Initialize(IServiceProvider services, out IService service)
    {
        service = services.GetService<IService>();
    }
}

snippet source | anchor

What gets generated

//HintName: PostConstructWithOutParameter.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

partial class PostConstructWithOutParameter
{
	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public PostConstructWithOutParameter(
		global::IOtherService otherService,
		global::IServiceProvider services
	)
	{
		this._otherService = otherService;
		Initialize(services, out this._service);
	}
}

snippet source | anchor

Optional Parameters

[AutoConstruct]
public partial class PostConstructWithDefaultParameter
{
    [AutoPostConstruct]
    private void Initialize(Service? service = default)
    {
    }
}

snippet source | anchor

What gets generated

//HintName: PostConstructWithDefaultParameter.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

partial class PostConstructWithDefaultParameter
{
	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public PostConstructWithDefaultParameter(global::Service service = default)
	{
		Initialize(service);
	}
}

snippet source | anchor

Back to Contents

Argument Guards

Null guards for the arguments to the constructor can be added in 2 ways.

In your project you can add a AutoCtorGuards property.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <AutoCtorGuards>true</AutoCtorGuards>
  </PropertyGroup>

</Project>

OR

In each AutoConstruct attribute you can add a setting to enable/disable guards.

[AutoConstruct(GuardSetting.Enabled)]
public partial class Guarded
{
    private readonly IService _service;
}

snippet source | anchor

What gets generated

//HintName: Guarded.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

partial class Guarded
{
	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public Guarded(global::IService service)
	{
		this._service = service ?? throw new global::System.ArgumentNullException("service");
	}
}

snippet source | anchor

Back to Contents

Keyed Services

When using Microsoft.Extensions.DependencyInjection you can mark fields and properties with [AutoKeyedService] and it will be included in the constructor.

[AutoConstruct]
public partial class Keyed
{
    [AutoKeyedService("key")]
    private readonly IService _keyedService;
}

snippet source | anchor

What gets generated

//HintName: Keyed.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

partial class Keyed
{
	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public Keyed(
		[global::Microsoft.Extensions.DependencyInjection.FromKeyedServices("key")] global::IService keyedService
	)
	{
		this._keyedService = keyedService;
	}
}

snippet source | anchor

Back to Contents

Service Provider

[ServiceProvider]
[Singleton<IClock, Clock>]
[Singleton<IGreeter, Greeter>]
public sealed partial class Container;

[AutoConstruct]
public partial class Greeter : IGreeter
{
    private readonly IClock _clock;
}

snippet source | anchor

What gets generated

//HintName: Container.ServiceProvider.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

partial class Container : 
	global::System.IServiceProvider,
	global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService,
	global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider,
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService,
	global::System.IDisposable,
	Container.IResolver<global::IClock>,
	Container.IResolver<global::IGreeter>,
	Container.IResolver<global::System.Collections.Generic.IEnumerable<global::IClock>>,
	Container.IResolver<global::System.Collections.Generic.IEnumerable<global::IGreeter>>,
	Container.IResolver<global::System.IServiceProvider>,
	Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>,
	Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>,
	Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>,
	Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>

{
	private readonly object _lock = new object();
	private global::System.Collections.Generic.List<object>? _disposables;

	private volatile global::IClock? _S0;
	private global::IClock S0()
	{
		var service = _S0;
		if (service is not null)
			return service;
		lock (_lock)
			return (_S0 ??= new global::Clock());
	}
	private volatile global::IGreeter? _S1;
	private global::IGreeter S1()
	{
		var service = _S1;
		if (service is not null)
			return service;
		lock (_lock)
			return (_S1 ??= new global::Greeter(S0()));
	}

	private object? Resolve(global::System.Type type, object? key, bool probe)
	{
		if (key is null)
		{
			if (type == typeof(global::IClock))
				return probe ? this : (object)(S0());
			if (type == typeof(global::IGreeter))
				return probe ? this : (object)(S1());
			if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IClock>))
				return probe ? this : (object)(new global::IClock[] { S0() });
			if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IGreeter>))
				return probe ? this : (object)(new global::IGreeter[] { S1() });
			if (type == typeof(global::System.IServiceProvider))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService))
				return probe ? this : (object)(this);
			return null;
		}
		return null;
	}

	private global::System.IServiceProvider? Fallback => null;

	public object? GetService(global::System.Type serviceType)
		=> GetKeyedService(serviceType, null);

	public object? GetKeyedService(global::System.Type serviceType, object? serviceKey)
		=> Resolve(serviceType, serviceKey, false)
		?? (serviceKey == null ? Fallback?.GetService(serviceType) : (Fallback as global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey));

	public object GetRequiredKeyedService(global::System.Type serviceType, object? serviceKey)
		=> GetKeyedService(serviceType, serviceKey)
		?? throw new global::System.InvalidOperationException("No service for type '" + serviceType + "' has been registered.");

	public T? GetService<T>()
		=> this is Container.IResolver<T> resolver ? resolver.Get() : GetService(typeof(T)) is T service ? service : default;

	public T GetRequiredService<T>()
		=> this is Container.IResolver<T> resolver ? resolver.Get() : (T)GetRequiredKeyedService(typeof(T), null);

	private interface IResolver<T> { T Get(); }
	global::IClock Container.IResolver<global::IClock>.Get()
		=> S0();
	global::IGreeter Container.IResolver<global::IGreeter>.Get()
		=> S1();
	global::System.Collections.Generic.IEnumerable<global::IClock> Container.IResolver<global::System.Collections.Generic.IEnumerable<global::IClock>>.Get()
		=> new global::IClock[] { S0() };
	global::System.Collections.Generic.IEnumerable<global::IGreeter> Container.IResolver<global::System.Collections.Generic.IEnumerable<global::IGreeter>>.Get()
		=> new global::IGreeter[] { S1() };
	global::System.IServiceProvider Container.IResolver<global::System.IServiceProvider>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>.Get()
		=> this;

	public bool IsService(global::System.Type serviceType)
		=> IsKeyedService(serviceType, null);

	public bool IsKeyedService(global::System.Type serviceType, object? serviceKey)
		=> Resolve(serviceType, serviceKey, true) != null || (serviceKey == null ? (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)?.IsService(serviceType) == true : (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) == true);

	public Scope CreateScope() => new Scope(this);
	global::Microsoft.Extensions.DependencyInjection.IServiceScope global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope() => CreateScope();

	private static T Required<T>(object? service)
		=> service is T t ? t : throw new global::System.InvalidOperationException("No service for type '" + typeof(T) + "' has been registered.");

	private T Track<T>(T service)
	{
		if (service is global::System.IDisposable)
			lock (_lock)
				(_disposables ??= new global::System.Collections.Generic.List<object>()).Add(service);
		return service;
	}

	private object[] Drain()
	{
		lock (_lock)
		{
			var items = _disposables?.ToArray() ?? new object[0];
			_disposables = null;
			global::System.Array.Reverse(items);
			return items;
		}
	}

	public void Dispose()
	{
		foreach (var item in Drain())
		{
			if (item is global::System.IDisposable disposable)
			{
				disposable.Dispose();
			}
		}
	}

	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public sealed class Scope : 
		global::System.IServiceProvider,
		global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService,
		global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider,
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService,
		global::System.IDisposable,
		global::Microsoft.Extensions.DependencyInjection.IServiceScope,
		Container.IResolver<global::IClock>,
		Container.IResolver<global::IGreeter>,
		Container.IResolver<global::System.Collections.Generic.IEnumerable<global::IClock>>,
		Container.IResolver<global::System.Collections.Generic.IEnumerable<global::IGreeter>>,
		Container.IResolver<global::System.IServiceProvider>,
		Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>,
		Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>,
		Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>,
		Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>
	
	{
		private readonly object _lock = new object();
		private global::System.Collections.Generic.List<object>? _disposables;
		private readonly Container _root;
		public Scope(Container root) => _root = root;
		public global::System.IServiceProvider ServiceProvider => this;

		private global::IClock S0() => _root.S0();
		private global::IGreeter S1() => _root.S1();

		private object? Resolve(global::System.Type type, object? key, bool probe)
		{
			if (key is null)
			{
				if (type == typeof(global::IClock))
					return probe ? this : (object)(S0());
				if (type == typeof(global::IGreeter))
					return probe ? this : (object)(S1());
				if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IClock>))
					return probe ? this : (object)(new global::IClock[] { S0() });
				if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IGreeter>))
					return probe ? this : (object)(new global::IGreeter[] { S1() });
				if (type == typeof(global::System.IServiceProvider))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService))
					return probe ? this : (object)(this);
				return null;
			}
			return null;
		}

		private global::System.IServiceProvider? Fallback => null;

		public object? GetService(global::System.Type serviceType)
			=> GetKeyedService(serviceType, null);

		public object? GetKeyedService(global::System.Type serviceType, object? serviceKey)
			=> Resolve(serviceType, serviceKey, false)
			?? (serviceKey == null ? Fallback?.GetService(serviceType) : (Fallback as global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey));

		public object GetRequiredKeyedService(global::System.Type serviceType, object? serviceKey)
			=> GetKeyedService(serviceType, serviceKey)
			?? throw new global::System.InvalidOperationException("No service for type '" + serviceType + "' has been registered.");

		public T? GetService<T>()
			=> this is Container.IResolver<T> resolver ? resolver.Get() : GetService(typeof(T)) is T service ? service : default;

		public T GetRequiredService<T>()
			=> this is Container.IResolver<T> resolver ? resolver.Get() : (T)GetRequiredKeyedService(typeof(T), null);

		global::IClock Container.IResolver<global::IClock>.Get()
			=> S0();
		global::IGreeter Container.IResolver<global::IGreeter>.Get()
			=> S1();
		global::System.Collections.Generic.IEnumerable<global::IClock> Container.IResolver<global::System.Collections.Generic.IEnumerable<global::IClock>>.Get()
			=> new global::IClock[] { S0() };
		global::System.Collections.Generic.IEnumerable<global::IGreeter> Container.IResolver<global::System.Collections.Generic.IEnumerable<global::IGreeter>>.Get()
			=> new global::IGreeter[] { S1() };
		global::System.IServiceProvider Container.IResolver<global::System.IServiceProvider>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService Container.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>.Get()
			=> this;

		public bool IsService(global::System.Type serviceType)
			=> IsKeyedService(serviceType, null);

		public bool IsKeyedService(global::System.Type serviceType, object? serviceKey)
			=> Resolve(serviceType, serviceKey, true) != null || (serviceKey == null ? (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)?.IsService(serviceType) == true : (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) == true);

		public Scope CreateScope() => new Scope(_root);
		global::Microsoft.Extensions.DependencyInjection.IServiceScope global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope() => CreateScope();

		private static T Required<T>(object? service)
			=> service is T t ? t : throw new global::System.InvalidOperationException("No service for type '" + typeof(T) + "' has been registered.");

		private T Track<T>(T service)
		{
			if (service is global::System.IDisposable)
				lock (_lock)
					(_disposables ??= new global::System.Collections.Generic.List<object>()).Add(service);
			return service;
		}

		private object[] Drain()
		{
			lock (_lock)
			{
				var items = _disposables?.ToArray() ?? new object[0];
				_disposables = null;
				global::System.Array.Reverse(items);
				return items;
			}
		}

		public void Dispose()
		{
			foreach (var item in Drain())
			{
				if (item is global::System.IDisposable disposable)
				{
					disposable.Dispose();
				}
			}
		}
	}
}

snippet source | anchor

Add [ServiceProvider] to a blank partial class and register services with [Singleton], [Transient] or [Scoped] attributes.

The service provider is fully generated at compile time so there is no runtime reflection.

Multiple registrations for the same service can be returned with IEnumerable<T>. When getting just one the last registration wins.

Scanning

As well as registering services individually there is also an option to scan for services. Scanning is performed at compile time.

[ServiceProvider]
[ScanTransient(typeof(IHandler<>))]
public sealed partial class OrderContainer;

public interface IHandler<TMessage>;

public class CreateOrderHandler : IHandler<CreateOrder>;
public class CancelOrderHandler : IHandler<CancelOrder>;

snippet source | anchor

What gets generated

//HintName: OrderContainer.ServiceProvider.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

partial class OrderContainer : 
	global::System.IServiceProvider,
	global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService,
	global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider,
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService,
	global::System.IDisposable,
	OrderContainer.IResolver<global::IHandler<global::CancelOrder>>,
	OrderContainer.IResolver<global::IHandler<global::CreateOrder>>,
	OrderContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IHandler<global::CancelOrder>>>,
	OrderContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IHandler<global::CreateOrder>>>,
	OrderContainer.IResolver<global::System.IServiceProvider>,
	OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>,
	OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>,
	OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>,
	OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>

{
	private readonly object _lock = new object();
	private global::System.Collections.Generic.List<object>? _disposables;

	private global::IHandler<global::CancelOrder> S0() => new global::CancelOrderHandler();
	private global::IHandler<global::CreateOrder> S1() => new global::CreateOrderHandler();

	private object? Resolve(global::System.Type type, object? key, bool probe)
	{
		if (key is null)
		{
			if (type == typeof(global::IHandler<global::CancelOrder>))
				return probe ? this : (object)(S0());
			if (type == typeof(global::IHandler<global::CreateOrder>))
				return probe ? this : (object)(S1());
			if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IHandler<global::CancelOrder>>))
				return probe ? this : (object)(new global::IHandler<global::CancelOrder>[] { S0() });
			if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IHandler<global::CreateOrder>>))
				return probe ? this : (object)(new global::IHandler<global::CreateOrder>[] { S1() });
			if (type == typeof(global::System.IServiceProvider))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService))
				return probe ? this : (object)(this);
			return null;
		}
		return null;
	}

	private global::System.IServiceProvider? Fallback => null;

	public object? GetService(global::System.Type serviceType)
		=> GetKeyedService(serviceType, null);

	public object? GetKeyedService(global::System.Type serviceType, object? serviceKey)
		=> Resolve(serviceType, serviceKey, false)
		?? (serviceKey == null ? Fallback?.GetService(serviceType) : (Fallback as global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey));

	public object GetRequiredKeyedService(global::System.Type serviceType, object? serviceKey)
		=> GetKeyedService(serviceType, serviceKey)
		?? throw new global::System.InvalidOperationException("No service for type '" + serviceType + "' has been registered.");

	public T? GetService<T>()
		=> this is OrderContainer.IResolver<T> resolver ? resolver.Get() : GetService(typeof(T)) is T service ? service : default;

	public T GetRequiredService<T>()
		=> this is OrderContainer.IResolver<T> resolver ? resolver.Get() : (T)GetRequiredKeyedService(typeof(T), null);

	private interface IResolver<T> { T Get(); }
	global::IHandler<global::CancelOrder> OrderContainer.IResolver<global::IHandler<global::CancelOrder>>.Get()
		=> S0();
	global::IHandler<global::CreateOrder> OrderContainer.IResolver<global::IHandler<global::CreateOrder>>.Get()
		=> S1();
	global::System.Collections.Generic.IEnumerable<global::IHandler<global::CancelOrder>> OrderContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IHandler<global::CancelOrder>>>.Get()
		=> new global::IHandler<global::CancelOrder>[] { S0() };
	global::System.Collections.Generic.IEnumerable<global::IHandler<global::CreateOrder>> OrderContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IHandler<global::CreateOrder>>>.Get()
		=> new global::IHandler<global::CreateOrder>[] { S1() };
	global::System.IServiceProvider OrderContainer.IResolver<global::System.IServiceProvider>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>.Get()
		=> this;

	public bool IsService(global::System.Type serviceType)
		=> IsKeyedService(serviceType, null);

	public bool IsKeyedService(global::System.Type serviceType, object? serviceKey)
		=> Resolve(serviceType, serviceKey, true) != null || (serviceKey == null ? (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)?.IsService(serviceType) == true : (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) == true);

	public Scope CreateScope() => new Scope(this);
	global::Microsoft.Extensions.DependencyInjection.IServiceScope global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope() => CreateScope();

	private static T Required<T>(object? service)
		=> service is T t ? t : throw new global::System.InvalidOperationException("No service for type '" + typeof(T) + "' has been registered.");

	private T Track<T>(T service)
	{
		if (service is global::System.IDisposable)
			lock (_lock)
				(_disposables ??= new global::System.Collections.Generic.List<object>()).Add(service);
		return service;
	}

	private object[] Drain()
	{
		lock (_lock)
		{
			var items = _disposables?.ToArray() ?? new object[0];
			_disposables = null;
			global::System.Array.Reverse(items);
			return items;
		}
	}

	public void Dispose()
	{
		foreach (var item in Drain())
		{
			if (item is global::System.IDisposable disposable)
			{
				disposable.Dispose();
			}
		}
	}

	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public sealed class Scope : 
		global::System.IServiceProvider,
		global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService,
		global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider,
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService,
		global::System.IDisposable,
		global::Microsoft.Extensions.DependencyInjection.IServiceScope,
		OrderContainer.IResolver<global::IHandler<global::CancelOrder>>,
		OrderContainer.IResolver<global::IHandler<global::CreateOrder>>,
		OrderContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IHandler<global::CancelOrder>>>,
		OrderContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IHandler<global::CreateOrder>>>,
		OrderContainer.IResolver<global::System.IServiceProvider>,
		OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>,
		OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>,
		OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>,
		OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>
	
	{
		private readonly object _lock = new object();
		private global::System.Collections.Generic.List<object>? _disposables;
		private readonly OrderContainer _root;
		public Scope(OrderContainer root) => _root = root;
		public global::System.IServiceProvider ServiceProvider => this;

		private global::IHandler<global::CancelOrder> S0() => new global::CancelOrderHandler();
		private global::IHandler<global::CreateOrder> S1() => new global::CreateOrderHandler();

		private object? Resolve(global::System.Type type, object? key, bool probe)
		{
			if (key is null)
			{
				if (type == typeof(global::IHandler<global::CancelOrder>))
					return probe ? this : (object)(S0());
				if (type == typeof(global::IHandler<global::CreateOrder>))
					return probe ? this : (object)(S1());
				if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IHandler<global::CancelOrder>>))
					return probe ? this : (object)(new global::IHandler<global::CancelOrder>[] { S0() });
				if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IHandler<global::CreateOrder>>))
					return probe ? this : (object)(new global::IHandler<global::CreateOrder>[] { S1() });
				if (type == typeof(global::System.IServiceProvider))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService))
					return probe ? this : (object)(this);
				return null;
			}
			return null;
		}

		private global::System.IServiceProvider? Fallback => null;

		public object? GetService(global::System.Type serviceType)
			=> GetKeyedService(serviceType, null);

		public object? GetKeyedService(global::System.Type serviceType, object? serviceKey)
			=> Resolve(serviceType, serviceKey, false)
			?? (serviceKey == null ? Fallback?.GetService(serviceType) : (Fallback as global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey));

		public object GetRequiredKeyedService(global::System.Type serviceType, object? serviceKey)
			=> GetKeyedService(serviceType, serviceKey)
			?? throw new global::System.InvalidOperationException("No service for type '" + serviceType + "' has been registered.");

		public T? GetService<T>()
			=> this is OrderContainer.IResolver<T> resolver ? resolver.Get() : GetService(typeof(T)) is T service ? service : default;

		public T GetRequiredService<T>()
			=> this is OrderContainer.IResolver<T> resolver ? resolver.Get() : (T)GetRequiredKeyedService(typeof(T), null);

		global::IHandler<global::CancelOrder> OrderContainer.IResolver<global::IHandler<global::CancelOrder>>.Get()
			=> S0();
		global::IHandler<global::CreateOrder> OrderContainer.IResolver<global::IHandler<global::CreateOrder>>.Get()
			=> S1();
		global::System.Collections.Generic.IEnumerable<global::IHandler<global::CancelOrder>> OrderContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IHandler<global::CancelOrder>>>.Get()
			=> new global::IHandler<global::CancelOrder>[] { S0() };
		global::System.Collections.Generic.IEnumerable<global::IHandler<global::CreateOrder>> OrderContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IHandler<global::CreateOrder>>>.Get()
			=> new global::IHandler<global::CreateOrder>[] { S1() };
		global::System.IServiceProvider OrderContainer.IResolver<global::System.IServiceProvider>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService OrderContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>.Get()
			=> this;

		public bool IsService(global::System.Type serviceType)
			=> IsKeyedService(serviceType, null);

		public bool IsKeyedService(global::System.Type serviceType, object? serviceKey)
			=> Resolve(serviceType, serviceKey, true) != null || (serviceKey == null ? (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)?.IsService(serviceType) == true : (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) == true);

		public Scope CreateScope() => new Scope(_root);
		global::Microsoft.Extensions.DependencyInjection.IServiceScope global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope() => CreateScope();

		private static T Required<T>(object? service)
			=> service is T t ? t : throw new global::System.InvalidOperationException("No service for type '" + typeof(T) + "' has been registered.");

		private T Track<T>(T service)
		{
			if (service is global::System.IDisposable)
				lock (_lock)
					(_disposables ??= new global::System.Collections.Generic.List<object>()).Add(service);
			return service;
		}

		private object[] Drain()
		{
			lock (_lock)
			{
				var items = _disposables?.ToArray() ?? new object[0];
				_disposables = null;
				global::System.Array.Reverse(items);
				return items;
			}
		}

		public void Dispose()
		{
			foreach (var item in Drain())
			{
				if (item is global::System.IDisposable disposable)
				{
					disposable.Dispose();
				}
			}
		}
	}
}

snippet source | anchor

The scan attributes [ScanSingleton], [ScanTransient], and [ScanScoped] have some options.

  • As determines what to register the service as: ScanAs.Service, the service being scanned for (default); ScanAs.Self, the type itself; ScanAs.ImplementedInterfaces, all the interfaces the type has.
  • FromAssembliesOf can be used to scan other assemblies instead of the one the provider is in; add the provider too to keep it in the list of assemblies to scan.
  • TypeNameFilter only includes types whose name matches, where * matches anything and ? any one character, e.g. "*Repository". The service can be left out to select by name alone.

Keyed Services

[ServiceProvider]
[Singleton<IClient, LiveClient>(Key = "live")]
[Singleton<IClient, SandboxClient>(Key = "sandbox")]
[Singleton<IPaymentGateway, PaymentGateway>]
public sealed partial class PaymentContainer;

public interface IPaymentGateway;

public class PaymentGateway : IPaymentGateway
{
    public PaymentGateway([AutoKeyedService("live")] IClient client) { }
}

snippet source | anchor

What gets generated

//HintName: PaymentContainer.ServiceProvider.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

partial class PaymentContainer : 
	global::System.IServiceProvider,
	global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService,
	global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider,
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService,
	global::System.IDisposable,
	PaymentContainer.IResolver<global::IPaymentGateway>,
	PaymentContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IPaymentGateway>>,
	PaymentContainer.IResolver<global::System.IServiceProvider>,
	PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>,
	PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>,
	PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>,
	PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>

{
	private readonly object _lock = new object();
	private global::System.Collections.Generic.List<object>? _disposables;

	private volatile global::IClient? _S0;
	private global::IClient S0()
	{
		var service = _S0;
		if (service is not null)
			return service;
		lock (_lock)
			return (_S0 ??= new global::LiveClient());
	}
	private volatile global::IClient? _S1;
	private global::IClient S1()
	{
		var service = _S1;
		if (service is not null)
			return service;
		lock (_lock)
			return (_S1 ??= new global::SandboxClient());
	}
	private volatile global::IPaymentGateway? _S2;
	private global::IPaymentGateway S2()
	{
		var service = _S2;
		if (service is not null)
			return service;
		lock (_lock)
			return (_S2 ??= new global::PaymentGateway(S0()));
	}

	private object? Resolve(global::System.Type type, object? key, bool probe)
	{
		if (key is null)
		{
			if (type == typeof(global::IPaymentGateway))
				return probe ? this : (object)(S2());
			if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IPaymentGateway>))
				return probe ? this : (object)(new global::IPaymentGateway[] { S2() });
			if (type == typeof(global::System.IServiceProvider))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService))
				return probe ? this : (object)(this);
			return null;
		}
		if (type == typeof(global::IClient) && object.Equals(key, "live"))
			return probe ? this : (object)(S0());
		if (type == typeof(global::IClient) && object.Equals(key, "sandbox"))
			return probe ? this : (object)(S1());
		if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IClient>) && object.Equals(key, "live"))
			return probe ? this : (object)(new global::IClient[] { S0() });
		if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IClient>) && object.Equals(key, "sandbox"))
			return probe ? this : (object)(new global::IClient[] { S1() });
		if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IClient>) && object.Equals(key, global::Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey))
			return probe ? this : (object)(new global::IClient[] { S0(), S1() });
		return null;
	}

	private global::System.IServiceProvider? Fallback => null;

	public object? GetService(global::System.Type serviceType)
		=> GetKeyedService(serviceType, null);

	public object? GetKeyedService(global::System.Type serviceType, object? serviceKey)
		=> Resolve(serviceType, serviceKey, false)
		?? (serviceKey == null ? Fallback?.GetService(serviceType) : (Fallback as global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey));

	public object GetRequiredKeyedService(global::System.Type serviceType, object? serviceKey)
		=> GetKeyedService(serviceType, serviceKey)
		?? throw new global::System.InvalidOperationException("No service for type '" + serviceType + "' has been registered.");

	public T? GetService<T>()
		=> this is PaymentContainer.IResolver<T> resolver ? resolver.Get() : GetService(typeof(T)) is T service ? service : default;

	public T GetRequiredService<T>()
		=> this is PaymentContainer.IResolver<T> resolver ? resolver.Get() : (T)GetRequiredKeyedService(typeof(T), null);

	private interface IResolver<T> { T Get(); }
	global::IPaymentGateway PaymentContainer.IResolver<global::IPaymentGateway>.Get()
		=> S2();
	global::System.Collections.Generic.IEnumerable<global::IPaymentGateway> PaymentContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IPaymentGateway>>.Get()
		=> new global::IPaymentGateway[] { S2() };
	global::System.IServiceProvider PaymentContainer.IResolver<global::System.IServiceProvider>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>.Get()
		=> this;

	public bool IsService(global::System.Type serviceType)
		=> IsKeyedService(serviceType, null);

	public bool IsKeyedService(global::System.Type serviceType, object? serviceKey)
		=> Resolve(serviceType, serviceKey, true) != null || (serviceKey == null ? (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)?.IsService(serviceType) == true : (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) == true);

	public Scope CreateScope() => new Scope(this);
	global::Microsoft.Extensions.DependencyInjection.IServiceScope global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope() => CreateScope();

	private static T Required<T>(object? service)
		=> service is T t ? t : throw new global::System.InvalidOperationException("No service for type '" + typeof(T) + "' has been registered.");

	private T Track<T>(T service)
	{
		if (service is global::System.IDisposable)
			lock (_lock)
				(_disposables ??= new global::System.Collections.Generic.List<object>()).Add(service);
		return service;
	}

	private object[] Drain()
	{
		lock (_lock)
		{
			var items = _disposables?.ToArray() ?? new object[0];
			_disposables = null;
			global::System.Array.Reverse(items);
			return items;
		}
	}

	public void Dispose()
	{
		foreach (var item in Drain())
		{
			if (item is global::System.IDisposable disposable)
			{
				disposable.Dispose();
			}
		}
	}

	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public sealed class Scope : 
		global::System.IServiceProvider,
		global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService,
		global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider,
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService,
		global::System.IDisposable,
		global::Microsoft.Extensions.DependencyInjection.IServiceScope,
		PaymentContainer.IResolver<global::IPaymentGateway>,
		PaymentContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IPaymentGateway>>,
		PaymentContainer.IResolver<global::System.IServiceProvider>,
		PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>,
		PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>,
		PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>,
		PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>
	
	{
		private readonly object _lock = new object();
		private global::System.Collections.Generic.List<object>? _disposables;
		private readonly PaymentContainer _root;
		public Scope(PaymentContainer root) => _root = root;
		public global::System.IServiceProvider ServiceProvider => this;

		private global::IClient S0() => _root.S0();
		private global::IClient S1() => _root.S1();
		private global::IPaymentGateway S2() => _root.S2();

		private object? Resolve(global::System.Type type, object? key, bool probe)
		{
			if (key is null)
			{
				if (type == typeof(global::IPaymentGateway))
					return probe ? this : (object)(S2());
				if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IPaymentGateway>))
					return probe ? this : (object)(new global::IPaymentGateway[] { S2() });
				if (type == typeof(global::System.IServiceProvider))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService))
					return probe ? this : (object)(this);
				return null;
			}
			if (type == typeof(global::IClient) && object.Equals(key, "live"))
				return probe ? this : (object)(S0());
			if (type == typeof(global::IClient) && object.Equals(key, "sandbox"))
				return probe ? this : (object)(S1());
			if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IClient>) && object.Equals(key, "live"))
				return probe ? this : (object)(new global::IClient[] { S0() });
			if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IClient>) && object.Equals(key, "sandbox"))
				return probe ? this : (object)(new global::IClient[] { S1() });
			if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IClient>) && object.Equals(key, global::Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey))
				return probe ? this : (object)(new global::IClient[] { S0(), S1() });
			return null;
		}

		private global::System.IServiceProvider? Fallback => null;

		public object? GetService(global::System.Type serviceType)
			=> GetKeyedService(serviceType, null);

		public object? GetKeyedService(global::System.Type serviceType, object? serviceKey)
			=> Resolve(serviceType, serviceKey, false)
			?? (serviceKey == null ? Fallback?.GetService(serviceType) : (Fallback as global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey));

		public object GetRequiredKeyedService(global::System.Type serviceType, object? serviceKey)
			=> GetKeyedService(serviceType, serviceKey)
			?? throw new global::System.InvalidOperationException("No service for type '" + serviceType + "' has been registered.");

		public T? GetService<T>()
			=> this is PaymentContainer.IResolver<T> resolver ? resolver.Get() : GetService(typeof(T)) is T service ? service : default;

		public T GetRequiredService<T>()
			=> this is PaymentContainer.IResolver<T> resolver ? resolver.Get() : (T)GetRequiredKeyedService(typeof(T), null);

		global::IPaymentGateway PaymentContainer.IResolver<global::IPaymentGateway>.Get()
			=> S2();
		global::System.Collections.Generic.IEnumerable<global::IPaymentGateway> PaymentContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IPaymentGateway>>.Get()
			=> new global::IPaymentGateway[] { S2() };
		global::System.IServiceProvider PaymentContainer.IResolver<global::System.IServiceProvider>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService PaymentContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>.Get()
			=> this;

		public bool IsService(global::System.Type serviceType)
			=> IsKeyedService(serviceType, null);

		public bool IsKeyedService(global::System.Type serviceType, object? serviceKey)
			=> Resolve(serviceType, serviceKey, true) != null || (serviceKey == null ? (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)?.IsService(serviceType) == true : (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) == true);

		public Scope CreateScope() => new Scope(_root);
		global::Microsoft.Extensions.DependencyInjection.IServiceScope global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope() => CreateScope();

		private static T Required<T>(object? service)
			=> service is T t ? t : throw new global::System.InvalidOperationException("No service for type '" + typeof(T) + "' has been registered.");

		private T Track<T>(T service)
		{
			if (service is global::System.IDisposable)
				lock (_lock)
					(_disposables ??= new global::System.Collections.Generic.List<object>()).Add(service);
			return service;
		}

		private object[] Drain()
		{
			lock (_lock)
			{
				var items = _disposables?.ToArray() ?? new object[0];
				_disposables = null;
				global::System.Array.Reverse(items);
				return items;
			}
		}

		public void Dispose()
		{
			foreach (var item in Drain())
			{
				if (item is global::System.IDisposable disposable)
				{
					disposable.Dispose();
				}
			}
		}
	}
}

snippet source | anchor

Factories

[ServiceProvider]
[Singleton<IClock>(Factory = nameof(CreateClock))]
[Singleton<IBanner>(Factory = nameof(_banner))]
[Scoped<IAuditLog>(Factory = nameof(CreateAuditLog))]
public sealed partial class HostContainer
{
    private readonly IBanner _banner = new Banner("AutoCtor");

    private IClock CreateClock() => new SystemClock("UTC");

    private IAuditLog CreateAuditLog(System.IServiceProvider services) => new AuditLog(services);
}

snippet source | anchor

What gets generated

//HintName: HostContainer.ServiceProvider.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

partial class HostContainer : 
	global::System.IServiceProvider,
	global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService,
	global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider,
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService,
	global::System.IDisposable,
	HostContainer.IResolver<global::IClock>,
	HostContainer.IResolver<global::IBanner>,
	HostContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IClock>>,
	HostContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IBanner>>,
	HostContainer.IResolver<global::System.IServiceProvider>,
	HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>,
	HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>,
	HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>,
	HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>

{
	private readonly object _lock = new object();
	private global::System.Collections.Generic.List<object>? _disposables;

	private volatile global::IClock? _S0;
	private global::IClock S0()
	{
		var service = _S0;
		if (service is not null)
			return service;
		lock (_lock)
			return (_S0 ??= Track<global::IClock>(this.CreateClock()));
	}
	private volatile global::IBanner? _S1;
	private global::IBanner S1()
	{
		var service = _S1;
		if (service is not null)
			return service;
		lock (_lock)
			return (_S1 ??= Track<global::IBanner>(this._banner));
	}

	private object? Resolve(global::System.Type type, object? key, bool probe)
	{
		if (key is null)
		{
			if (type == typeof(global::IClock))
				return probe ? this : (object)(S0());
			if (type == typeof(global::IBanner))
				return probe ? this : (object)(S1());
			if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IClock>))
				return probe ? this : (object)(new global::IClock[] { S0() });
			if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IBanner>))
				return probe ? this : (object)(new global::IBanner[] { S1() });
			if (type == typeof(global::System.IServiceProvider))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService))
				return probe ? this : (object)(this);
			return null;
		}
		return null;
	}

	private global::System.IServiceProvider? Fallback => null;

	public object? GetService(global::System.Type serviceType)
		=> GetKeyedService(serviceType, null);

	public object? GetKeyedService(global::System.Type serviceType, object? serviceKey)
		=> Resolve(serviceType, serviceKey, false)
		?? (serviceKey == null ? Fallback?.GetService(serviceType) : (Fallback as global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey));

	public object GetRequiredKeyedService(global::System.Type serviceType, object? serviceKey)
		=> GetKeyedService(serviceType, serviceKey)
		?? throw new global::System.InvalidOperationException("No service for type '" + serviceType + "' has been registered.");

	public T? GetService<T>()
		=> this is HostContainer.IResolver<T> resolver ? resolver.Get() : GetService(typeof(T)) is T service ? service : default;

	public T GetRequiredService<T>()
		=> this is HostContainer.IResolver<T> resolver ? resolver.Get() : (T)GetRequiredKeyedService(typeof(T), null);

	private interface IResolver<T> { T Get(); }
	global::IClock HostContainer.IResolver<global::IClock>.Get()
		=> S0();
	global::IBanner HostContainer.IResolver<global::IBanner>.Get()
		=> S1();
	global::System.Collections.Generic.IEnumerable<global::IClock> HostContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IClock>>.Get()
		=> new global::IClock[] { S0() };
	global::System.Collections.Generic.IEnumerable<global::IBanner> HostContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IBanner>>.Get()
		=> new global::IBanner[] { S1() };
	global::System.IServiceProvider HostContainer.IResolver<global::System.IServiceProvider>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>.Get()
		=> this;

	public bool IsService(global::System.Type serviceType)
		=> IsKeyedService(serviceType, null);

	public bool IsKeyedService(global::System.Type serviceType, object? serviceKey)
		=> Resolve(serviceType, serviceKey, true) != null || (serviceKey == null ? (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)?.IsService(serviceType) == true : (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) == true);

	public Scope CreateScope() => new Scope(this);
	global::Microsoft.Extensions.DependencyInjection.IServiceScope global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope() => CreateScope();

	private static T Required<T>(object? service)
		=> service is T t ? t : throw new global::System.InvalidOperationException("No service for type '" + typeof(T) + "' has been registered.");

	private T Track<T>(T service)
	{
		if (service is global::System.IDisposable)
			lock (_lock)
				(_disposables ??= new global::System.Collections.Generic.List<object>()).Add(service);
		return service;
	}

	private object[] Drain()
	{
		lock (_lock)
		{
			var items = _disposables?.ToArray() ?? new object[0];
			_disposables = null;
			global::System.Array.Reverse(items);
			return items;
		}
	}

	public void Dispose()
	{
		foreach (var item in Drain())
		{
			if (item is global::System.IDisposable disposable)
			{
				disposable.Dispose();
			}
		}
	}

	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public sealed class Scope : 
		global::System.IServiceProvider,
		global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService,
		global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider,
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService,
		global::System.IDisposable,
		global::Microsoft.Extensions.DependencyInjection.IServiceScope,
		HostContainer.IResolver<global::IClock>,
		HostContainer.IResolver<global::IBanner>,
		HostContainer.IResolver<global::IAuditLog>,
		HostContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IClock>>,
		HostContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IBanner>>,
		HostContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IAuditLog>>,
		HostContainer.IResolver<global::System.IServiceProvider>,
		HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>,
		HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>,
		HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>,
		HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>
	
	{
		private readonly object _lock = new object();
		private global::System.Collections.Generic.List<object>? _disposables;
		private readonly HostContainer _root;
		public Scope(HostContainer root) => _root = root;
		public global::System.IServiceProvider ServiceProvider => this;

		private global::IClock S0() => _root.S0();
		private global::IBanner S1() => _root.S1();
		private volatile global::IAuditLog? _S2;
		private global::IAuditLog S2()
		{
			var service = _S2;
			if (service is not null)
				return service;
			lock (_lock)
				return (_S2 ??= Track<global::IAuditLog>(_root.CreateAuditLog(this)));
		}

		private object? Resolve(global::System.Type type, object? key, bool probe)
		{
			if (key is null)
			{
				if (type == typeof(global::IClock))
					return probe ? this : (object)(S0());
				if (type == typeof(global::IBanner))
					return probe ? this : (object)(S1());
				if (type == typeof(global::IAuditLog))
					return probe ? this : (object)(S2());
				if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IClock>))
					return probe ? this : (object)(new global::IClock[] { S0() });
				if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IBanner>))
					return probe ? this : (object)(new global::IBanner[] { S1() });
				if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IAuditLog>))
					return probe ? this : (object)(new global::IAuditLog[] { S2() });
				if (type == typeof(global::System.IServiceProvider))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService))
					return probe ? this : (object)(this);
				return null;
			}
			return null;
		}

		private global::System.IServiceProvider? Fallback => null;

		public object? GetService(global::System.Type serviceType)
			=> GetKeyedService(serviceType, null);

		public object? GetKeyedService(global::System.Type serviceType, object? serviceKey)
			=> Resolve(serviceType, serviceKey, false)
			?? (serviceKey == null ? Fallback?.GetService(serviceType) : (Fallback as global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey));

		public object GetRequiredKeyedService(global::System.Type serviceType, object? serviceKey)
			=> GetKeyedService(serviceType, serviceKey)
			?? throw new global::System.InvalidOperationException("No service for type '" + serviceType + "' has been registered.");

		public T? GetService<T>()
			=> this is HostContainer.IResolver<T> resolver ? resolver.Get() : GetService(typeof(T)) is T service ? service : default;

		public T GetRequiredService<T>()
			=> this is HostContainer.IResolver<T> resolver ? resolver.Get() : (T)GetRequiredKeyedService(typeof(T), null);

		global::IClock HostContainer.IResolver<global::IClock>.Get()
			=> S0();
		global::IBanner HostContainer.IResolver<global::IBanner>.Get()
			=> S1();
		global::IAuditLog HostContainer.IResolver<global::IAuditLog>.Get()
			=> S2();
		global::System.Collections.Generic.IEnumerable<global::IClock> HostContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IClock>>.Get()
			=> new global::IClock[] { S0() };
		global::System.Collections.Generic.IEnumerable<global::IBanner> HostContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IBanner>>.Get()
			=> new global::IBanner[] { S1() };
		global::System.Collections.Generic.IEnumerable<global::IAuditLog> HostContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IAuditLog>>.Get()
			=> new global::IAuditLog[] { S2() };
		global::System.IServiceProvider HostContainer.IResolver<global::System.IServiceProvider>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService HostContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>.Get()
			=> this;

		public bool IsService(global::System.Type serviceType)
			=> IsKeyedService(serviceType, null);

		public bool IsKeyedService(global::System.Type serviceType, object? serviceKey)
			=> Resolve(serviceType, serviceKey, true) != null || (serviceKey == null ? (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)?.IsService(serviceType) == true : (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) == true);

		public Scope CreateScope() => new Scope(_root);
		global::Microsoft.Extensions.DependencyInjection.IServiceScope global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope() => CreateScope();

		private static T Required<T>(object? service)
			=> service is T t ? t : throw new global::System.InvalidOperationException("No service for type '" + typeof(T) + "' has been registered.");

		private T Track<T>(T service)
		{
			if (service is global::System.IDisposable)
				lock (_lock)
					(_disposables ??= new global::System.Collections.Generic.List<object>()).Add(service);
			return service;
		}

		private object[] Drain()
		{
			lock (_lock)
			{
				var items = _disposables?.ToArray() ?? new object[0];
				_disposables = null;
				global::System.Array.Reverse(items);
				return items;
			}
		}

		public void Dispose()
		{
			foreach (var item in Drain())
			{
				if (item is global::System.IDisposable disposable)
				{
					disposable.Dispose();
				}
			}
		}
	}
}

snippet source | anchor

Falling back to another provider

Fallback on [ServiceProvider] names a member to use when there is no registration for that service.

[ServiceProvider(Fallback = nameof(_host))]
[Singleton<IGreeter, Greeter>]
public sealed partial class FallbackContainer
{
    private readonly System.IServiceProvider _host;

    public FallbackContainer(System.IServiceProvider host) => _host = host;
}

snippet source | anchor

What gets generated

//HintName: FallbackContainer.ServiceProvider.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

partial class FallbackContainer : 
	global::System.IServiceProvider,
	global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService,
	global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider,
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService,
	global::System.IDisposable,
	FallbackContainer.IResolver<global::IGreeter>,
	FallbackContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IGreeter>>,
	FallbackContainer.IResolver<global::System.IServiceProvider>,
	FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>,
	FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>,
	FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>,
	FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>

{
	private readonly object _lock = new object();
	private global::System.Collections.Generic.List<object>? _disposables;

	private volatile global::IGreeter? _S0;
	private global::IGreeter S0()
	{
		var service = _S0;
		if (service is not null)
			return service;
		lock (_lock)
			return (_S0 ??= new global::Greeter(Required<global::ILogSink>(GetKeyedService(typeof(global::ILogSink), null))));
	}

	private object? Resolve(global::System.Type type, object? key, bool probe)
	{
		if (key is null)
		{
			if (type == typeof(global::IGreeter))
				return probe ? this : (object)(S0());
			if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IGreeter>))
				return probe ? this : (object)(new global::IGreeter[] { S0() });
			if (type == typeof(global::System.IServiceProvider))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService))
				return probe ? this : (object)(this);
			return null;
		}
		return null;
	}

	private global::System.IServiceProvider? Fallback => this._host;

	public object? GetService(global::System.Type serviceType)
		=> GetKeyedService(serviceType, null);

	public object? GetKeyedService(global::System.Type serviceType, object? serviceKey)
		=> Resolve(serviceType, serviceKey, false)
		?? (serviceKey == null ? Fallback?.GetService(serviceType) : (Fallback as global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey));

	public object GetRequiredKeyedService(global::System.Type serviceType, object? serviceKey)
		=> GetKeyedService(serviceType, serviceKey)
		?? throw new global::System.InvalidOperationException("No service for type '" + serviceType + "' has been registered.");

	public T? GetService<T>()
		=> this is FallbackContainer.IResolver<T> resolver ? resolver.Get() : GetService(typeof(T)) is T service ? service : default;

	public T GetRequiredService<T>()
		=> this is FallbackContainer.IResolver<T> resolver ? resolver.Get() : (T)GetRequiredKeyedService(typeof(T), null);

	private interface IResolver<T> { T Get(); }
	global::IGreeter FallbackContainer.IResolver<global::IGreeter>.Get()
		=> S0();
	global::System.Collections.Generic.IEnumerable<global::IGreeter> FallbackContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IGreeter>>.Get()
		=> new global::IGreeter[] { S0() };
	global::System.IServiceProvider FallbackContainer.IResolver<global::System.IServiceProvider>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>.Get()
		=> this;

	public bool IsService(global::System.Type serviceType)
		=> IsKeyedService(serviceType, null);

	public bool IsKeyedService(global::System.Type serviceType, object? serviceKey)
		=> Resolve(serviceType, serviceKey, true) != null || (serviceKey == null ? (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)?.IsService(serviceType) == true : (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) == true);

	public Scope CreateScope() => new Scope(this);
	global::Microsoft.Extensions.DependencyInjection.IServiceScope global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope() => CreateScope();

	private static T Required<T>(object? service)
		=> service is T t ? t : throw new global::System.InvalidOperationException("No service for type '" + typeof(T) + "' has been registered.");

	private T Track<T>(T service)
	{
		if (service is global::System.IDisposable)
			lock (_lock)
				(_disposables ??= new global::System.Collections.Generic.List<object>()).Add(service);
		return service;
	}

	private object[] Drain()
	{
		lock (_lock)
		{
			var items = _disposables?.ToArray() ?? new object[0];
			_disposables = null;
			global::System.Array.Reverse(items);
			return items;
		}
	}

	public void Dispose()
	{
		foreach (var item in Drain())
		{
			if (item is global::System.IDisposable disposable)
			{
				disposable.Dispose();
			}
		}
	}

	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public sealed class Scope : 
		global::System.IServiceProvider,
		global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService,
		global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider,
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService,
		global::System.IDisposable,
		global::Microsoft.Extensions.DependencyInjection.IServiceScope,
		FallbackContainer.IResolver<global::IGreeter>,
		FallbackContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IGreeter>>,
		FallbackContainer.IResolver<global::System.IServiceProvider>,
		FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>,
		FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>,
		FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>,
		FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>
	
	{
		private readonly object _lock = new object();
		private global::System.Collections.Generic.List<object>? _disposables;
		private readonly FallbackContainer _root;
		public Scope(FallbackContainer root) => _root = root;
		public global::System.IServiceProvider ServiceProvider => this;

		private global::IGreeter S0() => _root.S0();

		private object? Resolve(global::System.Type type, object? key, bool probe)
		{
			if (key is null)
			{
				if (type == typeof(global::IGreeter))
					return probe ? this : (object)(S0());
				if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IGreeter>))
					return probe ? this : (object)(new global::IGreeter[] { S0() });
				if (type == typeof(global::System.IServiceProvider))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService))
					return probe ? this : (object)(this);
				return null;
			}
			return null;
		}

		private global::System.IServiceProvider? _fallback;
		private global::System.IServiceProvider? Fallback { get { lock (_lock) return _fallback ??= _root._host is global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory f ? Track(f.CreateScope()).ServiceProvider : _root._host; } }

		public object? GetService(global::System.Type serviceType)
			=> GetKeyedService(serviceType, null);

		public object? GetKeyedService(global::System.Type serviceType, object? serviceKey)
			=> Resolve(serviceType, serviceKey, false)
			?? (serviceKey == null ? Fallback?.GetService(serviceType) : (Fallback as global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey));

		public object GetRequiredKeyedService(global::System.Type serviceType, object? serviceKey)
			=> GetKeyedService(serviceType, serviceKey)
			?? throw new global::System.InvalidOperationException("No service for type '" + serviceType + "' has been registered.");

		public T? GetService<T>()
			=> this is FallbackContainer.IResolver<T> resolver ? resolver.Get() : GetService(typeof(T)) is T service ? service : default;

		public T GetRequiredService<T>()
			=> this is FallbackContainer.IResolver<T> resolver ? resolver.Get() : (T)GetRequiredKeyedService(typeof(T), null);

		global::IGreeter FallbackContainer.IResolver<global::IGreeter>.Get()
			=> S0();
		global::System.Collections.Generic.IEnumerable<global::IGreeter> FallbackContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IGreeter>>.Get()
			=> new global::IGreeter[] { S0() };
		global::System.IServiceProvider FallbackContainer.IResolver<global::System.IServiceProvider>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService FallbackContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>.Get()
			=> this;

		public bool IsService(global::System.Type serviceType)
			=> IsKeyedService(serviceType, null);

		public bool IsKeyedService(global::System.Type serviceType, object? serviceKey)
			=> Resolve(serviceType, serviceKey, true) != null || (serviceKey == null ? (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)?.IsService(serviceType) == true : (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) == true);

		public Scope CreateScope() => new Scope(_root);
		global::Microsoft.Extensions.DependencyInjection.IServiceScope global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope() => CreateScope();

		private static T Required<T>(object? service)
			=> service is T t ? t : throw new global::System.InvalidOperationException("No service for type '" + typeof(T) + "' has been registered.");

		private T Track<T>(T service)
		{
			if (service is global::System.IDisposable)
				lock (_lock)
					(_disposables ??= new global::System.Collections.Generic.List<object>()).Add(service);
			return service;
		}

		private object[] Drain()
		{
			lock (_lock)
			{
				var items = _disposables?.ToArray() ?? new object[0];
				_disposables = null;
				global::System.Array.Reverse(items);
				return items;
			}
		}

		public void Dispose()
		{
			foreach (var item in Drain())
			{
				if (item is global::System.IDisposable disposable)
				{
					disposable.Dispose();
				}
			}
		}
	}
}

snippet source | anchor

Modules

[Import<TModule>] (or [Import(typeof(TModule))]) adds all the registrations from another type. Modules just act as markers so no code is generated for them.

[Singleton<IPaymentGateway, StripeGateway>]
[Scoped<ILedger>(Factory = nameof(CreateLedger))]
public class PaymentsModule
{
    public static ILedger CreateLedger(IPaymentGateway gateway) => new Ledger(gateway);
}

[ServiceProvider]
[Import<PaymentsModule>]
[Singleton<IPaymentGateway, FakeGateway>]
public sealed partial class TestContainer;

snippet source | anchor

What gets generated

//HintName: TestContainer.ServiceProvider.g.cs
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

partial class TestContainer : 
	global::System.IServiceProvider,
	global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService,
	global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider,
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService,
	global::System.IDisposable,
	TestContainer.IResolver<global::IPaymentGateway>,
	TestContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IPaymentGateway>>,
	TestContainer.IResolver<global::System.IServiceProvider>,
	TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>,
	TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>,
	TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>,
	TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>

{
	private readonly object _lock = new object();
	private global::System.Collections.Generic.List<object>? _disposables;

	private volatile global::IPaymentGateway? _S0;
	private global::IPaymentGateway S0()
	{
		var service = _S0;
		if (service is not null)
			return service;
		lock (_lock)
			return (_S0 ??= new global::StripeGateway());
	}
	private volatile global::IPaymentGateway? _S2;
	private global::IPaymentGateway S2()
	{
		var service = _S2;
		if (service is not null)
			return service;
		lock (_lock)
			return (_S2 ??= new global::FakeGateway());
	}

	private object? Resolve(global::System.Type type, object? key, bool probe)
	{
		if (key is null)
		{
			if (type == typeof(global::IPaymentGateway))
				return probe ? this : (object)(S2());
			if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IPaymentGateway>))
				return probe ? this : (object)(new global::IPaymentGateway[] { S0(), S2() });
			if (type == typeof(global::System.IServiceProvider))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider))
				return probe ? this : (object)(this);
			if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService))
				return probe ? this : (object)(this);
			return null;
		}
		return null;
	}

	private global::System.IServiceProvider? Fallback => null;

	public object? GetService(global::System.Type serviceType)
		=> GetKeyedService(serviceType, null);

	public object? GetKeyedService(global::System.Type serviceType, object? serviceKey)
		=> Resolve(serviceType, serviceKey, false)
		?? (serviceKey == null ? Fallback?.GetService(serviceType) : (Fallback as global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey));

	public object GetRequiredKeyedService(global::System.Type serviceType, object? serviceKey)
		=> GetKeyedService(serviceType, serviceKey)
		?? throw new global::System.InvalidOperationException("No service for type '" + serviceType + "' has been registered.");

	public T? GetService<T>()
		=> this is TestContainer.IResolver<T> resolver ? resolver.Get() : GetService(typeof(T)) is T service ? service : default;

	public T GetRequiredService<T>()
		=> this is TestContainer.IResolver<T> resolver ? resolver.Get() : (T)GetRequiredKeyedService(typeof(T), null);

	private interface IResolver<T> { T Get(); }
	global::IPaymentGateway TestContainer.IResolver<global::IPaymentGateway>.Get()
		=> S2();
	global::System.Collections.Generic.IEnumerable<global::IPaymentGateway> TestContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IPaymentGateway>>.Get()
		=> new global::IPaymentGateway[] { S0(), S2() };
	global::System.IServiceProvider TestContainer.IResolver<global::System.IServiceProvider>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>.Get()
		=> this;
	global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>.Get()
		=> this;

	public bool IsService(global::System.Type serviceType)
		=> IsKeyedService(serviceType, null);

	public bool IsKeyedService(global::System.Type serviceType, object? serviceKey)
		=> Resolve(serviceType, serviceKey, true) != null || (serviceKey == null ? (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)?.IsService(serviceType) == true : (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) == true);

	public Scope CreateScope() => new Scope(this);
	global::Microsoft.Extensions.DependencyInjection.IServiceScope global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope() => CreateScope();

	private static T Required<T>(object? service)
		=> service is T t ? t : throw new global::System.InvalidOperationException("No service for type '" + typeof(T) + "' has been registered.");

	private T Track<T>(T service)
	{
		if (service is global::System.IDisposable)
			lock (_lock)
				(_disposables ??= new global::System.Collections.Generic.List<object>()).Add(service);
		return service;
	}

	private object[] Drain()
	{
		lock (_lock)
		{
			var items = _disposables?.ToArray() ?? new object[0];
			_disposables = null;
			global::System.Array.Reverse(items);
			return items;
		}
	}

	public void Dispose()
	{
		foreach (var item in Drain())
		{
			if (item is global::System.IDisposable disposable)
			{
				disposable.Dispose();
			}
		}
	}

	[global::System.CodeDom.Compiler.GeneratedCode("AutoCtor", "0.0.0.0")]
	public sealed class Scope : 
		global::System.IServiceProvider,
		global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService,
		global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider,
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService,
		global::System.IDisposable,
		global::Microsoft.Extensions.DependencyInjection.IServiceScope,
		TestContainer.IResolver<global::IPaymentGateway>,
		TestContainer.IResolver<global::ILedger>,
		TestContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IPaymentGateway>>,
		TestContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::ILedger>>,
		TestContainer.IResolver<global::System.IServiceProvider>,
		TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>,
		TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>,
		TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>,
		TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>
	
	{
		private readonly object _lock = new object();
		private global::System.Collections.Generic.List<object>? _disposables;
		private readonly TestContainer _root;
		public Scope(TestContainer root) => _root = root;
		public global::System.IServiceProvider ServiceProvider => this;

		private global::IPaymentGateway S0() => _root.S0();
		private volatile global::ILedger? _S1;
		private global::ILedger S1()
		{
			var service = _S1;
			if (service is not null)
				return service;
			lock (_lock)
				return (_S1 ??= Track<global::ILedger>(global::PaymentsModule.CreateLedger(S2())));
		}
		private global::IPaymentGateway S2() => _root.S2();

		private object? Resolve(global::System.Type type, object? key, bool probe)
		{
			if (key is null)
			{
				if (type == typeof(global::IPaymentGateway))
					return probe ? this : (object)(S2());
				if (type == typeof(global::ILedger))
					return probe ? this : (object)(S1());
				if (type == typeof(global::System.Collections.Generic.IEnumerable<global::IPaymentGateway>))
					return probe ? this : (object)(new global::IPaymentGateway[] { S0(), S2() });
				if (type == typeof(global::System.Collections.Generic.IEnumerable<global::ILedger>))
					return probe ? this : (object)(new global::ILedger[] { S1() });
				if (type == typeof(global::System.IServiceProvider))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider))
					return probe ? this : (object)(this);
				if (type == typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService))
					return probe ? this : (object)(this);
				return null;
			}
			return null;
		}

		private global::System.IServiceProvider? Fallback => null;

		public object? GetService(global::System.Type serviceType)
			=> GetKeyedService(serviceType, null);

		public object? GetKeyedService(global::System.Type serviceType, object? serviceKey)
			=> Resolve(serviceType, serviceKey, false)
			?? (serviceKey == null ? Fallback?.GetService(serviceType) : (Fallback as global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)?.GetKeyedService(serviceType, serviceKey));

		public object GetRequiredKeyedService(global::System.Type serviceType, object? serviceKey)
			=> GetKeyedService(serviceType, serviceKey)
			?? throw new global::System.InvalidOperationException("No service for type '" + serviceType + "' has been registered.");

		public T? GetService<T>()
			=> this is TestContainer.IResolver<T> resolver ? resolver.Get() : GetService(typeof(T)) is T service ? service : default;

		public T GetRequiredService<T>()
			=> this is TestContainer.IResolver<T> resolver ? resolver.Get() : (T)GetRequiredKeyedService(typeof(T), null);

		global::IPaymentGateway TestContainer.IResolver<global::IPaymentGateway>.Get()
			=> S2();
		global::ILedger TestContainer.IResolver<global::ILedger>.Get()
			=> S1();
		global::System.Collections.Generic.IEnumerable<global::IPaymentGateway> TestContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::IPaymentGateway>>.Get()
			=> new global::IPaymentGateway[] { S0(), S2() };
		global::System.Collections.Generic.IEnumerable<global::ILedger> TestContainer.IResolver<global::System.Collections.Generic.IEnumerable<global::ILedger>>.Get()
			=> new global::ILedger[] { S1() };
		global::System.IServiceProvider TestContainer.IResolver<global::System.IServiceProvider>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider>.Get()
			=> this;
		global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService TestContainer.IResolver<global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService>.Get()
			=> this;

		public bool IsService(global::System.Type serviceType)
			=> IsKeyedService(serviceType, null);

		public bool IsKeyedService(global::System.Type serviceType, object? serviceKey)
			=> Resolve(serviceType, serviceKey, true) != null || (serviceKey == null ? (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsService)?.IsService(serviceType) == true : (Fallback as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService ?? Fallback?.GetService(typeof(global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)) as global::Microsoft.Extensions.DependencyInjection.IServiceProviderIsKeyedService)?.IsKeyedService(serviceType, serviceKey) == true);

		public Scope CreateScope() => new Scope(_root);
		global::Microsoft.Extensions.DependencyInjection.IServiceScope global::Microsoft.Extensions.DependencyInjection.IServiceScopeFactory.CreateScope() => CreateScope();

		private static T Required<T>(object? service)
			=> service is T t ? t : throw new global::System.InvalidOperationException("No service for type '" + typeof(T) + "' has been registered.");

		private T Track<T>(T service)
		{
			if (service is global::System.IDisposable)
				lock (_lock)
					(_disposables ??= new global::System.Collections.Generic.List<object>()).Add(service);
			return service;
		}

		private object[] Drain()
		{
			lock (_lock)
			{
				var items = _disposables?.ToArray() ?? new object[0];
				_disposables = null;
				global::System.Array.Reverse(items);
				return items;
			}
		}

		public void Dispose()
		{
			foreach (var item in Drain())
			{
				if (item is global::System.IDisposable disposable)
				{
					disposable.Dispose();
				}
			}
		}
	}
}

snippet source | anchor

A module can live in another assembly, but the registration attributes are [Conditional], so that assembly has to define AUTOCTOR_USAGES (see Keeping Attributes In Code) for them to be there to read.

Back to Contents

Other

Embedding The Attributes

By default, the [AutoConstruct] attributes referenced in your project are contained in an external dll. It is also possible to embed the attributes directly in your project. To do this, you must do two things:

  1. Define the constant AUTOCTOR_EMBED_ATTRIBUTES. This ensures the attributes are embedded in your project.
  2. Add compile to the list of excluded assets in your <PackageReference> element. This ensures the

README truncated. Read the full version on GitHub.