一种优化.Net依赖注入 (DI) 的方法

一种优化.Net依赖注入 (DI) 的方法

zeee 61 2024-04-25

说明

性能影响
当我们在提供一些底层框架类或者中间件时,为了方便使用者使用, 一般会实现自己的 DI 扩展,以注册框架的服务, 这些服务根据业务场景不同可能时 Scope 或者 Transient 的。

而因为不知道上层服务的使用环境,所以在这里有必要做性能管理,避免被多次调用多次构造注入而影响程序启动性能。

逻辑影响

如果多次调用服务注册,会向 ServiceCollection 中注册多个映射,最后获取时会查找到最后一个并实例化,所以一般都业务逻辑无影响。

在一些特殊情况下,重复添加映射可能会产生影响:

  • 构造函数有副作用。 例如在构造函数中改变某些全局状态
  • 依赖第三方DI容器。第三方容器的行为可能与.net官方的不一致

实现

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddMyService(this IServiceCollection services)
    {
        // 检查服务是否注册过,避免重复注册
        if (services.Any(service => service.ImplementationType == typeof(MyServiceProvider)))
            return services;

        services.AddSingleton<MyServiceProvider>();

        // 注册其他业务服务,这里可能会存在耗时的操作
        return services.AddScoped<IOterService, IOterService>();
    }

    private sealed class MyServiceProvider { }
}

解释

在这个 ServiceCollectionExtensions 类中,MyServiceProvider 类被用作一个标记,用于检查 AddDolphin 方法是否已经被调用过。

在 AddMyService 方法中,首先检查服务集合 services 中是否已经存在 MyServiceProvider 的实例。如果存在,那么 AddMyService 方法就直接返回,不再添加其他服务。这是为了防止 AddMyService 方法被重复调用,导致重复添加服务。

MyServiceProvider 类被定义为 sealed 是为了防止它被继承。因为它只是一个标记,没有任何方法或属性,所以没有必要让其他类继承它。在 C# 中,sealed 关键字可以用来防止一个类被继承,这可以提高运行时性能,并防止其他代码误用你的类。


# csharp # dotnet