using System.Collections.Immutable;
using System.Text;
using Dpz.Core.SourceGenerator.Models;

namespace Dpz.Core.SourceGenerator;

/// <summary>
/// 根据服务注册元数据生成 Microsoft.Extensions.DependencyInjection 注册源码。
/// </summary>
internal static class ServiceRegistrationSourceBuilder
{
    internal static string Generate(ImmutableArray<ServiceRegistration> registrations)
    {
        var source = new StringBuilder();
        source.AppendLine("// <auto-generated />");
        source.AppendLine("#nullable enable");
        source.AppendLine();
        source.AppendLine("namespace Dpz.Core.Service;");
        source.AppendLine();
        source.AppendLine("internal static partial class GeneratedServiceRegistration");
        source.AppendLine("{");
        source.AppendLine(
            "    internal static global::Microsoft.Extensions.DependencyInjection.IServiceCollection AddGeneratedRepositoryServices("
        );
        source.AppendLine(
            "        this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services"
        );
        source.AppendLine("    )");
        source.AppendLine("    {");

        foreach (var registration in registrations)
        {
            if (registration.Kind == RegistrationKind.HttpClient)
            {
                AppendHttpClientRegistration(source, registration);
                continue;
            }

            AppendServiceRegistration(source, registration);
        }

        source.AppendLine();
        source.AppendLine("        return services;");
        source.AppendLine("    }");
        source.AppendLine("}");
        return source.ToString();
    }

    private static void AppendServiceRegistration(
        StringBuilder source,
        ServiceRegistration registration
    )
    {
        if (registration.RequiresDecorator)
        {
            AppendLifetimeRegistration(
                source,
                registration.Lifetime,
                registration.ImplementationType
            );
            AppendLifetimeRegistration(
                source,
                registration.Lifetime,
                registration.ServiceType,
                registration.DecoratorType
            );
            return;
        }

        AppendLifetimeRegistration(
            source,
            registration.Lifetime,
            registration.ServiceType,
            registration.ImplementationType
        );
    }

    private static void AppendHttpClientRegistration(
        StringBuilder source,
        ServiceRegistration registration
    )
    {
        if (registration.RequiresDecorator)
        {
            source.Append(
                "        global::Microsoft.Extensions.DependencyInjection.HttpClientFactoryServiceCollectionExtensions.AddHttpClient<"
            );
            source.Append(registration.ImplementationType);
            AppendHttpClientOptions(source, registration);
            source.Append(
                "        global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddTransient<"
            );
            source.Append(registration.ServiceType);
            source.Append(", ");
            source.Append(registration.DecoratorType);
            source.AppendLine(">(services);");
            return;
        }

        source.Append(
            "        global::Microsoft.Extensions.DependencyInjection.HttpClientFactoryServiceCollectionExtensions.AddHttpClient<"
        );
        source.Append(registration.ServiceType);
        source.Append(", ");
        source.Append(registration.ImplementationType);
        AppendHttpClientOptions(source, registration);
    }

    private static void AppendLifetimeRegistration(
        StringBuilder source,
        ServiceLifetime lifetime,
        string serviceType
    )
    {
        source.Append(
            "        global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions."
        );
        source.Append(GetLifetimeMethodName(lifetime));
        source.Append("<");
        source.Append(serviceType);
        source.AppendLine(">(services);");
    }

    private static void AppendLifetimeRegistration(
        StringBuilder source,
        ServiceLifetime lifetime,
        string serviceType,
        string implementationType
    )
    {
        source.Append(
            "        global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions."
        );
        source.Append(GetLifetimeMethodName(lifetime));
        source.Append("<");
        source.Append(serviceType);
        source.Append(", ");
        source.Append(implementationType);
        source.AppendLine(">(services);");
    }

    private static void AppendHttpClientOptions(
        StringBuilder source,
        ServiceRegistration registration
    )
    {
        source.AppendLine(">(services, static (_, client) =>");
        source.AppendLine("        {");
        source.Append("            client.BaseAddress = new global::System.Uri(");
        source.Append(SymbolDisplay.ToCSharpStringLiteral(registration.BaseAddress!));
        source.AppendLine(");");

        if (registration.TimeoutSeconds > 0)
        {
            source.Append("            client.Timeout = global::System.TimeSpan.FromSeconds(");
            source.Append(registration.TimeoutSeconds);
            source.AppendLine(");");
        }

        source.AppendLine("        });");
    }

    private static string GetLifetimeMethodName(ServiceLifetime lifetime)
    {
        return lifetime == ServiceLifetime.Singleton ? "AddSingleton"
            : lifetime == ServiceLifetime.Transient ? "AddTransient"
            : "AddScoped";
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

代码解释

这是一个 C# 源代码生成器(Source Generator)的组成部分,用于自动生成依赖注入服务注册代码

主要功能

该类 ServiceRegistrationSourceBuilder 的作用是根据服务注册元数据,自动生成 Microsoft.Extensions.DependencyInjection 框架所需的服务注册代码。

核心方法

1. Generate 方法

  • 输入: 服务注册信息的不可变数组 ImmutableArray<ServiceRegistration>
  • 输出: 生成的 C# 源代码字符串
  • 功能:
    • 生成一个静态扩展方法 AddGeneratedRepositoryServices
    • 遍历所有服务注册信息,根据类型分别处理

2. AppendServiceRegistration 方法

处理普通服务注册,支持两种场景:

  • 带装饰器模式: 先注册实现类型,再注册装饰器
  • 普通注册: 直接注册服务接口与实现类型的映射

3. AppendHttpClientRegistration 方法

处理 HttpClient 类型的服务注册:

  • 使用 AddHttpClient 方法注册
  • 配置 BaseAddress(必需)
  • 可选配置 Timeout
  • 同样支持装饰器模式

4. AppendLifetimeRegistration 方法(两个重载)

  • 根据服务生命周期(Singleton/Scoped/Transient)生成对应的注册代码
  • 支持只注册实现类型或注册服务接口+实现类型

5. GetLifetimeMethodName 方法

根据生命周期枚举返回对应的 DI 方法名:

  • SingletonAddSingleton
  • TransientAddTransient
  • ScopedAddScoped

生成代码示例

生成的代码结构如下:

// <auto-generated />
#nullable enable

namespace Dpz.Core.Service;

internal static partial class GeneratedServiceRegistration
{
    internal static IServiceCollection AddGeneratedRepositoryServices(
        this IServiceCollection services)
    {
        // ... 自动生成的注册代码
        return services;
    }
}

特点

  1. 完全限定名称: 使用 global:: 前缀避免命名冲突
  2. 装饰器模式支持: 可以为服务添加装饰器层
  3. HttpClient 专用处理: 特别处理 HTTP 客户端的配置需求
  4. 类型安全: 在编译时生成强类型的注册代码

这是一个典型的 Roslyn Source Generator 应用场景,可以减少手动编写重复的服务注册代码。

评论加载中...