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

共享同一接口的抽象类依赖注入:ServiceBA注入为空的解决方法

依赖注入中ServiceBA注入为null的解决方法

问题背景

类层级结构

public abstract class ServiceBase<T> : IServiceBase
protected ServiceBase(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3)

public abstract class ServiceA<T> : ServiceBase<T>
protected ServiceA(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3) 
: base(extService1, extService2, extService3)

public abstract class ServiceAA : ServiceA<Type1>
protected ServiceAA(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3) 
: base(extService1, extService2, extService3)

public abstract class ServiceAB : ServiceA<Type2>
protected ServiceAB(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3) 
: base(extService1, extService2, extService3)

public abstract class ServiceB<T> : ServiceBase<Type3>
protected ServiceB(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3) 
: base(extService1, extService2, extService3)

public abstract class ServiceBA : ServiceB<Type1>
protected ServiceBA(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3) 
: base(extService1, extService2, extService3)

public abstract class ServiceBB : ServiceB<Type2>
protected ServiceBB(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3) 
: base(extService1, extService2, extService3)

现有依赖注入配置

...
builder.Services.AddScoped<IExtService1, extService1>();
builder.Services.AddScoped<IExtService2, extService2>();
builder.Services.AddScoped<IExtService3, extService3>();
builder.Services.AddScoped<IServiceBase, ServiceAA>();
builder.Services.AddScoped<IServiceBase, ServiceAB>();
builder.Services.AddScoped<IServiceBase, ServiceBA>();
builder.Services.AddScoped<IServiceBase, ServiceBB>();
...

需求与问题

想要在ServiceA<T>中注入ServiceBA,修改后的构造函数如下:

public abstract class ServiceA<T> : ServiceBase<T>
protected ServiceA(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3, ServiceBA<T> serviceBA) 
: base(extService1, extService2, extService3)

但注入后的serviceBA始终为null,需要解决这个问题。


问题原因与解决步骤

1. 核心问题:类型不匹配

首先看ServiceBA的定义:它是ServiceB<Type1>的抽象子类,没有泛型参数T,你试图注入ServiceBA<T>,但这个类型根本不存在,DI容器找不到匹配的服务,自然返回null。

2. 解决思路:调整类结构与DI配置

根据你的需求(ServiceA<Type1>对应ServiceBA,ServiceA<Type2>对应ServiceBB),提供两种可行方案:

方案一:将ServiceB子类改为泛型

把ServiceBA和ServiceBB改成泛型类,匹配ServiceA的T参数,同时提供具体实现类(DI无法实例化抽象类):

// 泛型抽象类
public abstract class ServiceBA<T> : ServiceB<T>
{
    protected ServiceBA(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3) 
        : base(extService1, extService2, extService3) { }
}

// Type1对应的具体实现
public class ServiceBAImpl : ServiceBA<Type1>
{
    public ServiceBAImpl(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3) 
        : base(extService1, extService2, extService3) { }
}

// 同理改造ServiceBB<T>和ServiceBBImpl

然后更新DI注册:

builder.Services.AddScoped(typeof(ServiceBA<>), typeof(ServiceBAImpl<>));
builder.Services.AddScoped(typeof(ServiceBB<>), typeof(ServiceBBImpl<>));

最后修正ServiceA<T>的构造函数:

public abstract class ServiceA<T> : ServiceBase<T>
{
    protected ServiceA(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3, ServiceBA<T> serviceBA) 
        : base(extService1, extService2, extService3)
    {
        // 这里serviceBA就能正常注入了
    }
}

方案二:为ServiceB子类定义专用接口

如果不需要泛型,给ServiceBA和ServiceBB分别定义专属接口,让DI能精准匹配:

// 定义专用接口
public interface IServiceBA : IServiceBase { }
public interface IServiceBB : IServiceBase { }

// 修改ServiceBA和ServiceBB实现对应接口
public abstract class ServiceBA : ServiceB<Type1>, IServiceBA
{
    protected ServiceBA(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3) 
        : base(extService1, extService2, extService3) { }
}

public abstract class ServiceBB : ServiceB<Type2>, IServiceBB
{
    protected ServiceBB(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3) 
        : base(extService1, extService2, extService3) { }
}

// 提供具体实现类
public class ServiceBAImpl : ServiceBA { /* 构造函数继承 */ }
public class ServiceBBImpl : ServiceBB { /* 构造函数继承 */ }

更新DI注册:

builder.Services.AddScoped<IServiceBA, ServiceBAImpl>();
builder.Services.AddScoped<IServiceBB, ServiceBBImpl>();

这种方案下,需要在ServiceAA和ServiceAB中分别注入对应的接口(因为ServiceA<T>无法直接区分T对应的服务):

// ServiceAA中注入IServiceBA
public abstract class ServiceAA : ServiceA<Type1>
{
    protected ServiceAA(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3, IServiceBA serviceBA) 
        : base(extService1, extService2, extService3)
    {
    }
}

// ServiceAB中注入IServiceBB
public abstract class ServiceAB : ServiceA<Type2>
{
    protected ServiceAB(IExtService1 extService1, IExtService2 extService2, IExtService3 extService3, IServiceBB serviceBB) 
        : base(extService1, extService2, extService3)
    {
    }
}

3. 关键注意点

  • 抽象类无法被DI直接实例化:所有抽象类(ServiceAA、ServiceAB、ServiceBA等)都必须有对应的具体实现类,DI容器只能创建具体类的实例。
  • 避免依赖混乱:不要直接注入具体类,优先使用接口,这样能降低耦合度,也方便DI容器管理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 12:37:04