Skip to content

xm-i/AutoDiAttributes

Repository files navigation

AutoDiAttributes

test

InjectAttribute を付与したクラスを自動的に IServiceCollection へ登録する C# Source Generator です。

特徴

  • Incremental Generator (IIncrementalGenerator) 採用 — 差分ビルドに対応し、高速にコード生成
  • クラス単位で DI ライフタイムを指定 (Transient / Scoped / Singleton)
  • サービス型(インターフェイス / 抽象クラス)を明示指定可能。省略時は実装型 = サービス型として登録
  • 同一クラスへの複数属性 (AllowMultiple = true) をサポートし、1 つの実装を複数のサービス型で登録可能
  • 属性ライブラリは netstandard2.0 対応 — 幅広い .NET バージョンで利用可能

プロジェクト構成

AutoDiAttributes/                  … 属性・列挙型を定義するライブラリ (netstandard2.0)
AutoDiAttributes.Generator/        … Incremental Source Generator (netstandard2.0)
AutoDiAttributes.Generator.Tests/  … テスト (xUnit + Shouldly, net10.0)
DebugProject/                      … デモ・動作確認用プロジェクト

クイックスタート

1. プロジェクトへの参照を追加

AutoDiAttributesAutoDiAttributes.Generator をソリューションに含めるか、NuGet パッケージとして参照します。

Note

AutoDiAttributes.Generator は Source Generator として参照する必要があります。

<ProjectReference Include="..\AutoDiAttributes.Generator\AutoDiAttributes.Generator.csproj"
                  OutputItemType="Analyzer"
                  ReferenceOutputAssembly="false" />

2. クラスに InjectAttribute を付与

using AutoDiAttributes;

// インターフェイスをサービス型として明示指定
[Inject(InjectServiceLifetime.Scoped, typeof(IMyService))]
public class MyService : IMyService
{
    // 実装
}

// サービス型を省略 → 実装型自身がサービスとして登録される
[Inject(InjectServiceLifetime.Singleton)]
public class ClockProvider
{
    // 実装
}

// 複数の属性を付与して、インターフェイスと実装型の両方を登録
[Inject(InjectServiceLifetime.Singleton, typeof(INotifier))]
[Inject(InjectServiceLifetime.Transient)]
public class NotifierService : INotifier
{
    // INotifier → Singleton、NotifierService → Transient として登録される
}

3. 生成されたメソッドを呼び出す

ビルドすると、アセンブリ名から導出された名前空間に DIRegistration クラスが自動生成されます。 アプリケーション起動時に拡張メソッド AddGeneratedServices() を呼び出してください。

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGeneratedServices(); // 生成された拡張メソッド

API リファレンス

InjectAttribute

namespace AutoDiAttributes;

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public sealed class InjectAttribute : Attribute
{
    public InjectAttribute(InjectServiceLifetime lifetime);
    public InjectAttribute(InjectServiceLifetime lifetime, Type serviceType);

    public InjectServiceLifetime Lifetime { get; }
    public Type? ServiceType { get; }
}
パラメータ 説明
lifetime DI ライフタイム。Transient (0) / Scoped (1) / Singleton (2)
serviceType 登録時のサービス型(インターフェイス / 抽象型)。省略時は実装クラス自身

InjectServiceLifetime

namespace AutoDiAttributes;

public enum InjectServiceLifetime
{
    Transient = 0,
    Scoped    = 1,
    Singleton = 2
}

Important

Microsoft.Extensions.DependencyInjection.ServiceLifetime ではなく、AutoDiAttributes 独自の列挙型を使用します。 これにより、属性ライブラリを netstandard2.0 のまま維持しつつ、DI フレームワークへの依存を排除しています。

生成されるコードの例

アセンブリ名が MyApp.Web の場合、以下のようなコードが生成されます。

// <auto-generated />
namespace MyApp.Web;
public static class DIRegistration
{
    public static void AddGeneratedServices(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services)
    {
        global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddScoped<global::MyApp.IMyService, global::MyApp.MyService>(services);
        global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::MyApp.ClockProvider, global::MyApp.ClockProvider>(services);
    }
}

名前空間のサニタイズ

生成コードの名前空間は、アセンブリ名から自動導出されます。 C# の識別子として不正な文字は以下のルールで変換されます:

アセンブリ名 生成される名前空間
MyApp MyApp
My.App My.App
123App _23App
My-App My_App
My..App My._App
(空 / null) GeneratedDI

属性の記述パターン

以下のいずれの書式でも正しく認識されます。

[Inject(...)]
[InjectAttribute(...)]
[AutoDiAttributes.Inject(...)]
[AutoDiAttributes.InjectAttribute(...)]
[global::AutoDiAttributes.Inject(...)]
[global::AutoDiAttributes.InjectAttribute(...)]

テストの実行

dotnet test

テストフレームワークには xUnit を、アサーションには Shouldly を使用しています。

トラブルシューティング

症状 原因 対処
生成クラスが見えない ビルド前の IntelliSense キャッシュ 一度リビルドし、obj 配下の生成物を確認
AddGeneratedServices() が見つからない 名前空間の import 不足 アセンブリ名に対応する名前空間を using に追加
期待する登録が無い 属性の名前空間が異なる / typo using AutoDiAttributes; を追加し、属性名を確認
ライフタイムが期待と違う 引数順序違い 第 1 引数 = InjectServiceLifetime、第 2 引数 = Type の順で指定

ライセンス

MIT

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages