Skip to content

Attributes reference

Every attribute, property and enum member in Immediate.Injections, with defaults and constraints.

5 min read

Everything in this package lives in the Immediate.Injections.Shared namespace.

TypeTargetMultiple?
RegisterSingletonAttribute, RegisterScopedAttribute, RegisterTransientAttributeClassYes
RegisterSingletonAttribute<TService> and the scoped/transient equivalentsClassYes
RegisterSingletonAttribute<TService, TImplementation> and equivalentsClassYes
RegistrationDefaultsAttributeAssemblyNo
RegisterServicesAttributeMethodNo
RegistrationStrategy (enum)
DuplicateStrategy (enum)

Lifetime attributes

The three lifetimes — RegisterSingleton, RegisterScoped, RegisterTransient — are three copies of the same surface. They differ only in the ServiceDescriptor lifetime emitted.

Properties by form

PropertyTypeNon-generic<TService><TService, TImplementation>
ServiceTypeType?Yes
RegistrationStrategyRegistrationStrategyYes
ServiceKeyobject?YesYesYes
Factorystring?YesYesYes
DuplicateStrategyDuplicateStrategyYesYesYes
UseProxyFactoryboolYesYesYes
Tagsstring[]?YesYesYes

All properties are init-only and set as named arguments; none of the attributes has a positional constructor.

ServiceType

The ServiceDescriptor.ServiceType for the registration. The attributed class must be assignable to it, or INJ0004. Mutually exclusive with RegistrationStrategy (INJ0003).

[RegisterSingleton(ServiceType = typeof(IClock))]
public sealed class SystemClock : IClock;

Accepts an unbound generic — typeof(IRepository<>) — which is the only way to register an open generic. See Open generics.

Setting ServiceType means the attribute does not inherit RegistrationDefaults.RegistrationStrategy; the effective strategy becomes None.

RegistrationStrategy

Which service types the class is registered as. See Registration strategies for the full behavior of each member.

Resolution order: the attribute’s value; else None if ServiceType is set; else RegistrationDefaults.RegistrationStrategy; else None.

ServiceKey

Makes the registration keyed — the emitted descriptor becomes KeyedSingleton, KeyedScoped or KeyedTransient. Any compile-time constant that C# accepts as an attribute argument works (string, enum member, integer). Writing ServiceKey = null explicitly produces an unkeyed registration.

[RegisterSingleton<INotificationSender>(ServiceKey = "email")]
public sealed class EmailNotificationSender : INotificationSender;

See Keyed services.

Factory

The name of a static method on the attributed class used as the implementation factory.

RegistrationRequired signature
Unkeyedstatic TSelf Method(IServiceProvider)
Keyedstatic TSelf Method(IServiceProvider, object)

The method must exist (INJ0009) with a matching signature (INJ0010). Not supported on a generic target class (INJ0012 when the service type is an unbound generic; silently dropped otherwise).

[RegisterSingleton(Factory = nameof(Create))]
public sealed class MyService
{
	public static MyService Create(IServiceProvider provider) => new();
}

DuplicateStrategy

Which IServiceCollection method the registration is added with. Resolution order: the attribute’s value; else RegistrationDefaults.DuplicateStrategy; else Append.

UseProxyFactory

When true, the registration’s implementation factory becomes ServiceProviderServiceExtensions.GetRequiredService<TImplementation> — or ServiceProviderKeyedServiceExtensions.GetRequiredKeyedService<TImplementation> for a keyed registration — instead of the implementation type.

A proxy registration does not register the implementation type; it must be paired with something that does.

Cannot proxy to self (INJ0007). Cannot be combined with Factory (INJ0011) except when the effective strategy is SelfAndImplementedInterfaces. Not supported on a generic target class (INJ0008 when the service type is an unbound generic; silently dropped otherwise).

Resolution order: the attribute’s value; else RegistrationDefaults.UseProxyFactory, but only when the attribute names no Factory; else false.

See Factories and proxies.

Tags

Tags for this registration, filtered by the arguments passed to AddXxxServices. Untagged registrations are always applied; calling with no tags applies everything. See Tagged registration.

[RegisterSingleton(Tags = ["worker", "background"])]
public sealed class BackgroundWorker;

Generic forms

RegisterXxx<TService> registers the attributed class as TService.

RegisterXxx<TService, TImplementation> registers TService against a specific closed construction of the attributed class; TImplementation must be a construction of that class (INJ0006) and the form is redundant on a non-generic class (INJ0005).

Neither generic form exposes ServiceType or RegistrationStrategy — the type arguments already supply that information.

RegistrationDefaultsAttribute

Assembly-level defaults. Not AllowMultiple.

PropertyTypeDefaultNotes
RegistrationStrategyRegistrationStrategyNoneIgnored by attributes that set ServiceType, and by both generic forms
DuplicateStrategyDuplicateStrategyAppendApplies to all forms
UseProxyFactoryboolfalseIgnored when the attribute names a Factory
AssemblyInfo.cs
[assembly: RegistrationDefaults(
	RegistrationStrategy = RegistrationStrategy.SelfAndImplementedInterfaces,
	UseProxyFactory = true
)]

See Assembly-wide defaults.

RegisterServicesAttribute

Marks a static method to be invoked from the generated AddXxxServices. No properties. Accepted signatures:

static void Method(IServiceCollection services);
static void Method(IServiceCollection services, ReadOnlySpan<string> tags);

Anything else is INJ0001. All such methods in the assembly are invoked. See Manual registration.

RegistrationStrategy

MemberValueRegisters as
None0The ServiceType if set, otherwise identical to Self. Sentinel — do not set explicitly
Self1The attributed class
ImplementedInterfaces2Every implemented interface, excluding IDisposable and IAsyncDisposable; not the class itself
SelfAndImplementedInterfaces3The class and every implemented interface, with no IDisposable exclusion

On a generic class, ImplementedInterfaces and SelfAndImplementedInterfaces include only interfaces whose arity matches the class’s and whose type arguments are the class’s own type parameters.

DuplicateStrategy

MemberValueGenerated callEffect
Append0ServiceCollectionDescriptorExtensions.AddAdds unconditionally
Skip1ServiceCollectionDescriptorExtensions.TryAddAdds only if the service type is not already registered
Replace2ServiceCollectionDescriptorExtensions.ReplaceRemoves the first existing descriptor for the service type, then adds

Generated API

AddXxxServices is the only public member the generator emits.

public static IServiceCollection AddXxxServices(
	this IServiceCollection services,
	params ReadOnlySpan<string> tags   // params string[] on C# 12 and below
);

It is declared on a public static partial class RegistrationServiceCollectionExtensions in the project’s root namespace, carrying [GeneratedCode("Immediate.Injections", "<version>")]. See How it works.