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

.NET Core控制台DI:多接口实现无法获取指定实例报错

问题根源

当你将多个实现类注册为同一个接口IMainAction的Transient服务时,.NET DI容器的默认行为是:每次请求IMainAction实例时,都会返回最后注册的那个实现类。

比如你的注册代码如果是这样:

builder.Services.AddTransient<IMainAction, CityStoreClass>();
builder.Services.AddTransient<IMainAction, ProvinceService>();

此时容器中IMainAction的"默认"实现是ProvinceService——不管你注入多少次IMainAction,拿到的都是ProvinceService实例。这就是你尝试把它强制转换为CityStoreClass时抛出类型转换异常的原因。

解决方案

根据你的需求,有几种可行的解决方式:

1. 使用带键(Keyed)的服务(.NET 6+支持)

通过给不同的实现类标记唯一键,注入时指定键来获取对应实例,避免依赖类型强制转换:

注册服务

builder.Services.AddKeyedTransient<IMainAction, CityStoreClass>("city");
builder.Services.AddKeyedTransient<IMainAction, ProvinceService>("province");

在App类中注入

public class App
{
    private readonly IMainAction _cityService;
    private readonly IMainAction _provinceService;

    // 使用[FromKeyedServices]指定要注入的实例键
    public App([FromKeyedServices("city")] IMainAction cityService,
               [FromKeyedServices("province")] IMainAction provinceService)
    {
        _cityService = cityService;
        _provinceService = provinceService;
    }

    public void Run()
    {
        _cityService.Run(); // 直接调用,无需强制转换
        _provinceService.Run();
    }
}

2. 注入IEnumerable<IMainAction>并筛选实例

如果你不想用键服务,可以注入所有IMainAction的实例集合,然后通过类型筛选出需要的实现:

注册服务(保持你原来的注册方式不变)

builder.Services.AddTransient<IMainAction, CityStoreClass>();
builder.Services.AddTransient<IMainAction, ProvinceService>();

在App类中筛选实例

public class App
{
    private readonly CityStoreClass _cityService;
    private readonly ProvinceService _provinceService;

    public App(IEnumerable<IMainAction> allMainActions)
    {
        _cityService = allMainActions.OfType<CityStoreClass>().FirstOrDefault()
            ?? throw new InvalidOperationException("未找到CityStoreClass的DI实例");
        _provinceService = allMainActions.OfType<ProvinceService>().FirstOrDefault()
            ?? throw new InvalidOperationException("未找到ProvinceService的DI实例");
    }

    public void Run()
    {
        _cityService.Run();
        _provinceService.Run();
    }
}

3. 直接注册并注入具体实现类

如果你的业务逻辑确实需要直接依赖具体类而非接口,可以跳过接口注册,直接注册实现类:

注册服务

builder.Services.AddTransient<CityStoreClass>();
builder.Services.AddTransient<ProvinceService>();

在App类中注入

public class App
{
    private readonly CityStoreClass _cityService;
    private readonly ProvinceService _provinceService;

    // 直接注入具体类型,完全避免接口映射的歧义
    public App(CityStoreClass cityService, ProvinceService provinceService)
    {
        _cityService = cityService;
        _provinceService = provinceService;
    }

    public void Run()
    {
        _cityService.Run();
        _provinceService.Run();
    }
}

内容的提问来源于stack exchange,提问作者Cyrus the Great

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 16:02:46