Field, Property, and Method Injection
SourceGen.Ioc generates factory method registration when [IocInject] attribute is used on fields, properties, methods, or constructor parameters.
NOTE
FieldInject is not enabled in the default SourceGenIocFeatures value. The default is Register,Container,PropertyInject,MethodInject. To use [IocInject] on fields, add FieldInject in your project configuration (see MSBuild Configuration):
<PropertyGroup>
<SourceGenIocFeatures>Register,Container,PropertyInject,FieldInject,MethodInject</SourceGenIocFeatures>
</PropertyGroup>Property & Field Injection
Use [IocInject] to inject dependencies into properties or fields:
[IocRegister<IMyService>]
internal class MyService : IMyService
{
[IocInject]
public ILogger Logger { get; init; } = null!;
[IocInject]
internal IConfiguration configuration = null!;
}Generated Code
// <auto-generated/>
services.AddSingleton<global::MyNamespace.MyService>((global::System.IServiceProvider sp) =>
{
var s0_p0 = sp.GetRequiredService<global::MyNamespace.ILogger>();
var s0_p1 = sp.GetRequiredService<global::MyNamespace.IConfiguration>();
var s0 = new global::MyNamespace.MyService() { Logger = s0_p0, configuration = s0_p1 };
return s0;
});
services.AddSingleton<global::MyNamespace.IMyService>((global::System.IServiceProvider sp) => sp.GetRequiredService<global::MyNamespace.MyService>());Method Injection
Use [IocInject] on a method to call it after object creation:
[IocRegister<IMyService>]
internal class MyService : IMyService
{
private ILogger logger = null!;
private IConfiguration config = null!;
// Must be void return type
[IocInject]
public void Initialize(ILogger logger, IConfiguration config)
{
this.logger = logger;
this.config = config;
}
}Generated Code
// <auto-generated/>
services.AddSingleton<global::MyNamespace.MyService>((global::System.IServiceProvider sp) =>
{
var s0_m0 = sp.GetRequiredService<global::MyNamespace.ILogger>();
var s0_m1 = sp.GetRequiredService<global::MyNamespace.IConfiguration>();
var s0 = new global::MyNamespace.MyService();
s0.Initialize(s0_m0, s0_m1);
return s0;
});
services.AddSingleton<global::MyNamespace.IMyService>((global::System.IServiceProvider sp) => sp.GetRequiredService<global::MyNamespace.MyService>());Constructor Selection
Use [IocInject] on a constructor to specify which constructor to use for DI:
[IocRegister<IMyService>]
internal class MyService(IDependency1 dep1, IDependency2 dep2) : IMyService
{
private readonly IDependency1 dep1 = dep1;
private readonly IDependency2 dep2 = dep2;
// Use this constructor instead of the primary constructor
[IocInject]
internal MyService(IDependency1 dep1)
: this(dep1, new DefaultDependency2())
{
}
}Generated Code
// <auto-generated/>
services.AddSingleton<global::MyNamespace.MyService>((global::System.IServiceProvider sp) =>
{
var p0 = sp.GetRequiredService<global::MyNamespace.IDependency1>();
var s0 = new global::MyNamespace.MyService(p0);
return s0;
});
services.AddSingleton<global::MyNamespace.IMyService>((global::System.IServiceProvider sp) => sp.GetRequiredService<global::MyNamespace.MyService>());NOTE
If [IocInject] does not exist on any constructor, there are 2 situations:
- If no need to generate factory method (no field/property/method injection or decorator), will let
IServiceProviderselect constructor. - If factory method generation is needed (due to field/property/method injection or decorator), will use primary constructor, then the constructor with the most parameters.
Diagnostics
| ID | Severity | Description |
|---|---|---|
| SGIOC007 | Error | Invalid [IocInject] usage. The attribute cannot be applied to static members, non-accessible members (private, protected, private protected — but protected internal is accepted), properties without a setter or with an inaccessible setter, readonly fields, generic methods, non-ordinary methods (e.g., constructors, operators), or methods that do not return void. |
| SGIOC022 | Warning | [IocInject] is ignored when the corresponding feature (PropertyInject, FieldInject, or MethodInject) is disabled in SourceGenIocFeatures. |
| SGIOC023 | Error | An element in the InjectMembers array is not in a recognized format. Each element must be nameof(member) or new object[] { nameof(member), key [, KeyType] }. |
| SGIOC024 | Error | A member specified via InjectMembers is not injectable (e.g., static, non-accessible members (private, protected, private protected — but protected internal is accepted), no setter or inaccessible setter, readonly field, generic method, non-ordinary method, or method that does not return void). |
InjectMembers: Attribute-Level Injection Without [IocInject]
When you cannot add [IocInject] directly to a type's members (e.g., a third-party type), use the InjectMembers property on [IocRegisterFor] to specify injection points from the registration site:
// Register ThirdPartyService without modifying it
[IocRegisterFor(typeof(ThirdPartyService),
InjectMembers = [nameof(ThirdPartyService.Logger)])]
public static class ThirdPartyModule { }Each element is one of:
| Format | Description |
|---|---|
nameof(T.Member) | Inject without a key (resolves T from the container) |
new object[] { nameof(T.Member), "key" } | Inject a keyed service |
new object[] { nameof(T.Member), nameof(SomeKey), KeyType.Csharp } | Inject using a C# expression key |
NOTE
When the same member is specified in both InjectMembers and via [IocInject] on the member itself, [IocInject] takes priority.