在抽象 class 的构造函数中调用 container.get() 时应用程序崩溃

Application crash when calling container.get() in abstract class's constructor

我目前正在尝试实现一个具有多个属性的基础 class。除了一个 属性 之外,所有的都使用 InversifyJS 的 @Inject 标签通过构造函数注入。我还通过构造函数中的 container.Get() 函数获取了一个实例。当我 运行 我的应用程序一切正常时,但是当应用程序收到请求时,应用程序崩溃而没有错误。

基础class

/**
 * Base class for all intent logic
 */
@injectable()
export default abstract class IntentBase implements IIntent {
  protected logger: ILogger;
  protected responseService: IResponseService;
  protected contextService: IContextService;
  protected fallbackIntent: IIntent;
  protected responseBuilder: IResponseBuilder;

  /**
   * Constructor
   * @param logger logger
   * @param responseService response service
   * @param contextService context service
   */
  constructor(
    @inject(TYPES.WinstonLogger) logger: ILogger,
    @inject(TYPES.ResponseService) responseService: IResponseService,
    @inject(TYPES.ContextService) contextService: IContextService,
    @inject(TYPES.ResponseBuilder) responseBuilder: IResponseBuilder,
  ) {
    this.logger = logger;
    this.responseService = responseService;
    this.contextService = contextService;
    this.responseBuilder = responseBuilder;
    this.fallbackIntent = container.get(TYPES.DefaultFallbackIntent); // <-- container.Get() line
  }

  /**
   * Override the standard fallback logic for an intent.
   * @param fallback fallback to set
   */
  setFallback(fallback: IIntent): void {
    this.fallbackIntent = fallback;
  }

当我取消注释 container.get(TYPES.DefaultFallbackIntent) 行时,我的应用程序可以正常接收请求并且不会崩溃。我尝试这种注入设置的原因是因为我想在构造函数中为每个子 class 设置一个默认行为。

有人能解释为什么我似乎无法注入这个 class 吗? 提前致谢

更新

inversify.config.ts

import DefaultFallbackIntent from "./src/bot/intents/fallbacks/defaultFallbackIntent";
import TextResponseRepository from "./src/repositories/textResponseRepository";
import SsmlResponseRepsitory from "./src/repositories/ssmlResponseRepository";
import ContextService from "./src/services/contextService";
import GoogleResponseBuilder from "./src/builders/googleResponseBuilder";

const container = new Container();

container.bind<IGoogleAssistantController>(TYPES.GoogleController).to(GoogleAssistantController);
container.bind<IResponseService>(TYPES.ResponseService).to(ResponseSerivce);
container.bind<IContextService>(TYPES.ContextService).to(ContextService);
container.bind<IResponseRepository>(TYPES.TextResponseRepository).to(TextResponseRepository);
container.bind<IResponseRepository>(TYPES.SsmlResponseRepository).to(SsmlResponseRepsitory);
container.bind<ILogger>(TYPES.WinstonLogger).to(WinstonLogger);

container.bind<IIntent>(TYPES.WelcomeIntent).to(WelcomeIntent);
container.bind<IIntent>(TYPES.DefaultFallbackIntent).to(DefaultFallbackIntent);
container.bind<IResponseBuilder>(TYPES.ResponseBuilder).to(GoogleResponseBuilder);

export { container };

默认回退意图

/**
 * Default fallback intent class
 */
@injectable()
export default class DefaultFallbackIntent extends IntentBase {
  invoke(conv: DialogflowConversation): DialogflowConversation {
    const response = this.responseService.getResponse("defaultFallback");
    return conv.ask(response);
  }
}

为了 container.get(<Type>) 工作,<Type> 必须在某个时间点 bound 到容器。在您的组合根目录(您设置容器的位置)中,您可以创建此绑定:

const container = new Container();
container.bind<IIntent>(TYPES.DefaultFallbackIntent)).to(<TheDefaultFallbackIntentClass>);

编辑:

从评论中的讨论看来,DefaultFallbackIntent 继承自 IntentBase 是问题所在,因为当时 DefaultFallbackIntent 被实例化(通过绑定),没有执行基本构造函数时,容器中不存在这样的实例。

解决方法是不从 IntentBase 继承,只实现接口并在此 class 中设置必填字段:

/**
 * Default fallback intent class
 */
@injectable()
export default class DefaultFallbackIntent implements IIntent {
protected logger: ILogger;
  private responseService: IResponseService;
  private contextService: IContextService;
  private fallbackIntent: IIntent;
  private responseBuilder: IResponseBuilder;

  invoke(conv: DialogflowConversation): DialogflowConversation {
    const response = this.responseService.getResponse("defaultFallback");
    return conv.ask(response);
  }
}

但是,更好的解决方案是创建另一个超级 class,其中包含默认回退意图和其他意图的所有必填字段,以减少重复代码。