Skip to content

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):

xml
<PropertyGroup>
  <SourceGenIocFeatures>Register,Container,PropertyInject,FieldInject,MethodInject</SourceGenIocFeatures>
</PropertyGroup>

Property & Field Injection

Use [IocInject] to inject dependencies into properties or fields:

csharp
[IocRegister<IMyService>]
internal class MyService : IMyService
{
    [IocInject]
    public ILogger Logger { get; init; } = null!;

    [IocInject]
    internal IConfiguration configuration = null!;
}
Generated Code
csharp
// <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:

csharp
[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
csharp
// <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:

csharp
[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
csharp
// <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 IServiceProvider select 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

IDSeverityDescription
SGIOC007ErrorInvalid [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.
SGIOC022Warning[IocInject] is ignored when the corresponding feature (PropertyInject, FieldInject, or MethodInject) is disabled in SourceGenIocFeatures.
SGIOC023ErrorAn element in the InjectMembers array is not in a recognized format. Each element must be nameof(member) or new object[] { nameof(member), key [, KeyType] }.
SGIOC024ErrorA 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:

csharp
// Register ThirdPartyService without modifying it
[IocRegisterFor(typeof(ThirdPartyService),
    InjectMembers = [nameof(ThirdPartyService.Logger)])]
public static class ThirdPartyModule { }

Each element is one of:

FormatDescription
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.


← Back to Overview

Released under the MIT License.