You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8依赖注入:注入特定泛型IValidator时无关实例被初始化求助

问题描述

我使用.NET 8搭配9.0版本的Microsoft.Extensions.DependencyInjection。我有一组实现IValidator<in TModel, in TContext>接口的类,均通过services.AddScoped<IValidator<WebStoreItemValidate, WebStoreItemValidationContext>, WebstoreIdIsValid>();注册到服务容器。之后在另一服务的构造函数中,以IEnumerable<IValidator<WebStoreItemValidate, WebStoreItemValidationContext>> validators为参数注入这些服务(需要多实例)。但问题是,每当注入该集合时,所有带有完全不同泛型参数的IValidator<>实现都会被实例化。由于这类实现数量多且各自依赖复杂,造成了显著性能开销。请问我操作有误导致无关类被初始化?若操作无误,该行为的目的是什么,如何规避?

解答

问题原因

你没有操作错误,这是.NET依赖注入容器的默认行为。当请求IEnumerable<T>时,容器会扫描所有已注册的服务,只要服务类型与T属于同一个开放泛型接口(即IValidator<,>),就会被纳入集合,即便它们的泛型参数完全不同。这个设计是为了简化开放泛型服务的批量注入场景,但在你的场景下会引发不必要的实例化开销。

规避方案

方案一:使用标记接口缩小范围

为特定泛型组合的验证器创建专属标记接口,让容器精准匹配目标服务:

// 定义专用标记接口,继承目标泛型接口
public interface IWebStoreItemValidator : IValidator<WebStoreItemValidate, WebStoreItemValidationContext> { }

// 修改验证器实现类,继承标记接口
public class WebstoreIdIsValid : IWebStoreItemValidator 
{
    // 原有验证逻辑保持不变
}

// 注册时使用标记接口
services.AddScoped<IWebStoreItemValidator, WebstoreIdIsValid>();

// 注入时直接请求标记接口的集合
public class YourService
{
    public YourService(IEnumerable<IWebStoreItemValidator> validators)
    {
        // 仅获取实现IWebStoreItemValidator的实例,无关验证器不会被实例化
    }
}

该方案最直观,通过强类型约束彻底避免无关服务的实例化。

方案二:使用键控服务(.NET 8+)

注册时为目标验证器指定唯一键,注入时按键筛选:

// 注册时指定键
services.AddKeyedScoped<IValidator<WebStoreItemValidate, WebStoreItemValidationContext>, WebstoreIdIsValid>("WebStoreItem");

// 注入时通过IServiceProvider获取键控服务
public class YourService
{
    private readonly IEnumerable<IValidator<WebStoreItemValidate, WebStoreItemValidationContext>> _validators;

    public YourService(IServiceProvider serviceProvider)
    {
        _validators = serviceProvider.GetKeyedServices<IValidator<WebStoreItemValidate, WebStoreItemValidationContext>>("WebStoreItem");
    }
}

此方案利用.NET 8新增的键控服务特性,精准获取指定组的验证器,无需遍历所有同开放泛型的服务。

方案三:自定义扩展方法精准获取

实现IServiceProvider扩展方法,直接获取指定闭包泛型的服务集合:

public static class ValidatorServiceExtensions
{
    public static IEnumerable<IValidator<TModel, TContext>> GetValidators<TModel, TContext>(this IServiceProvider provider)
    {
        return provider.GetServices(typeof(IValidator<TModel, TContext>))
            .Cast<IValidator<TModel, TContext>>();
    }
}

// 注入时使用扩展方法
public class YourService
{
    private readonly IEnumerable<IValidator<WebStoreItemValidate, WebStoreItemValidationContext>> _validators;

    public YourService(IServiceProvider serviceProvider)
    {
        _validators = serviceProvider.GetValidators<WebStoreItemValidate, WebStoreItemValidationContext>();
    }
}

该方法通过GetServices(Type)的精准匹配,仅实例化并返回目标泛型参数的验证器,不会触发其他无关服务的创建。

内容的提问来源于stack exchange,提问作者Icode4food

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 01:52:37