NestJS依赖注入报错:无法解析Population的Number类型依赖
NestJS遗传算法课程排程系统依赖注入错误解决
问题描述
使用NestJS开发基于遗传算法的课程排程系统,包含geneticalgorithm.ts、data.ts、population.ts、scheduleservice.ts、schedulemodule.ts等文件。在GeneticAlgorithm类的方法中,通过构造函数调用Population类时需要传入population.getSchedules().length作为数值参数,但启动应用时出现依赖注入错误。
错误日志
[Nest] 63732 - 11/11/2024, 6:51:23 PM LOG [NestFactory] Starting Nest application... [Nest] 63732 - 11/11/2024, 6:51:23 PM LOG [InstanceLoader] AppModule dependencies initialized +54ms [Nest] 63732 - 11/11/2024, 6:51:23 PM LOG [Instance Loader] Type Orm Module dependencies initialized +0ms [Nest] 63732 - 11/11/2024, 6:51:23 PM LOG [Instance Loader] Number dependencies initialized +1ms [Nest] 63732 - 11/11/2024, 6:51:23 PM ERROR [Exception Handler] Nest can't resolve dependencies of the Population (?, Data). Please make sure that the argument Number at index [0] is available in the ScheduleModule context. Potential solutions: - Is ScheduleModule a valid NestJS module? - If Number is a provider, is it part of the current ScheduleModule? - If Number is exported from a separate @Module, is that module imported within ScheduleModule? @Module({ imports: [ /* the Module containing Number */ ] })
相关代码文件
geneticalgorithm.ts
import { Injectable } from '@nestjs/common'; import { Data } from './data'; import { Population } from './population'; import { Schedule } from './schedule'; import { Driver } from './driver'; @Injectable() export class GeneticAlgorithm { private data: Data; constructor(data: Data) { this.data = data; } public evolve(population: Population): Population { return this.mutatePopulation(this.crossoverPopulation(population)); } private crossoverPopulation(population: Population): Population { const crossoverPopulation = new Population(population.getSchedules().length, this.data); for (let i = 0; i < Driver.NUMB_OF_ELITE_SCHEDULES; i++) { crossoverPopulation.getSchedules()[i] = population.getSchedules()[i]; } for (let i = Driver.NUMB_OF_ELITE_SCHEDULES; i < population.getSchedules().length; i++) { if (Driver.CROSSOVER_RATE > Math.random()) { const schedule1 = this.selectTournamentPopulation(population).sortByFitness().getSchedules()[0]; const schedule2 = this.selectTournamentPopulation(population).sortByFitness().getSchedules()[0]; crossoverPopulation.getSchedules()[i] = this.crossoverSchedule(schedule1, schedule2); } else { crossoverPopulation.getSchedules()[i] = population.getSchedules()[i]; } } return crossoverPopulation; } private crossoverSchedule(schedule1: Schedule, schedule2: Schedule): Schedule { const crossoverSchedule = new Schedule(this.data).initialize(); for (let i = 0; i < crossoverSchedule.getClasses().length; i++) { if (Math.random() > 0.5) { crossoverSchedule.getClasses()[i] = schedule1.getClasses()[i]; } else { crossoverSchedule.getClasses()[i] = schedule2.getClasses()[i]; } } return crossoverSchedule; } private mutatePopulation(population: Population): Population { const mutatePopulation = new Population(population.getSchedules().length, this.data); const schedules = mutatePopulation.getSchedules(); for (let i = 0; i < Driver.NUMB_OF_ELITE_SCHEDULES; i++) { schedules[i] = population.getSchedules()[i]; } for (let i = Driver.NUMB_OF_ELITE_SCHEDULES; i < population.getSchedules().length; i++) { schedules[i] = this.mutateSchedule(population.getSchedules()[i]); } return mutatePopulation; } private mutateSchedule(schedule: Schedule): Schedule { const mutateSchedule = new Schedule(this.data).initialize(); for (let i = 0; i < schedule.getClasses().length; i++) { if (Driver.MUTATION_RATE > Math.random()) { schedule.getClasses()[i] = mutateSchedule.getClasses()[i]; } } return schedule; } private selectTournamentPopulation(population: Population): Population { const tournamentPopulation = new Population(Driver.TOURNAMENT_SELECTION_SIZE, this.data); for (let i = 0; i < Driver.TOURNAMENT_SELECTION_SIZE; i++) { tournamentPopulation.getSchedules()[i] = population.getSchedules()[Math.floor(Math.random() * population.getSchedules().length)]; } return tournamentPopulation; } }
population.ts
import { Injectable } from '@nestjs/common'; import { Data } from './data'; import { Schedule } from './schedule'; @Injectable() export class Population { private schedules: Schedule[]; constructor(size: number, data: Data) { this.schedules = new Array<Schedule>(size); for (let i = 0; i < size; i++) { this.schedules[i] = new Schedule(data).initialize(); } } public getSchedules(): Schedule[] { return this.schedules; } public sortByFitness(): Population { this.schedules.sort((schedule1, schedule2) => { let returnValue = 0; if (schedule1.getFitness() > schedule2.getFitness()) returnValue = -1; else if (schedule1.getFitness() < schedule2.getFitness()) returnValue = 1; return returnValue; }); return this; } }
schedulemodule.ts
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Schedule } from './schedule.entity'; import { ScheduleService } from './schedule.service'; import { ScheduleController } from './schedule.controller'; import { ScheduleRepository } from './schedule.repository'; import { Data } from './data'; import { GeneticAlgorithm } from './genetic-algorithm'; import { Population } from './population'; import { Class } from './class.entity'; import { CourseModule } from '../course/course.module'; import { DepartmentModule } from '../department/department.module'; import { InstructorModule } from '../instructor/instructor.module'; import { MeetingTimeModule } from '../meeting-time/meeting-time.module'; import { RoomModule } from '../room/room.module'; @Module({ imports: [ TypeOrmModule.forFeature([Schedule, Class]), CourseModule, DepartmentModule, InstructorModule, MeetingTimeModule, RoomModule, ], providers: [ScheduleService, ScheduleRepository, Data, GeneticAlgorithm, Population], controllers: [ScheduleController], }) export class ScheduleModule {}
问题原因
Population类被标记为@Injectable(),NestJS会尝试通过依赖注入系统创建它的实例,但它的构造函数需要一个动态的number类型参数size,Nest无法自动解析原始类型的依赖。而且在GeneticAlgorithm中我们是手动实例化Population,根本不需要将其注册为可注入服务。
解决方案
1. 移除Population类的@Injectable()装饰器
修改population.ts,去掉@Injectable(),因为它是工具类,不需要Nest管理生命周期:
import { Data } from './data'; import { Schedule } from './schedule'; export class Population { private schedules: Schedule[]; constructor(size: number, data: Data) { this.schedules = new Array<Schedule>(size); for (let i = 0; i < size; i++) { this.schedules[i] = new Schedule(data).initialize(); } } public getSchedules(): Schedule[] { return this.schedules; } public sortByFitness(): Population { this.schedules.sort((schedule1, schedule2) => { let returnValue = 0; if (schedule1.getFitness() > schedule2.getFitness()) returnValue = -1; else if (schedule1.getFitness() < schedule2.getFitness()) returnValue = 1; return returnValue; }); return this; } }
2. 从ScheduleModule的providers中移除Population
修改schedulemodule.ts,将Population从providers数组中删除:
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Schedule } from './schedule.entity'; import { ScheduleService } from './schedule.service'; import { ScheduleController } from './schedule.controller'; import { ScheduleRepository } from './schedule.repository'; import { Data } from './data'; import { GeneticAlgorithm } from './genetic-algorithm'; import { Class } from './class.entity'; import { CourseModule } from '../course/course.module'; import { DepartmentModule } from '../department/department.module'; import { InstructorModule } from '../instructor/instructor.module'; import { MeetingTimeModule } from '../meeting-time/meeting-time.module'; import { RoomModule } from '../room/room.module'; @Module({ imports: [ TypeOrmModule.forFeature([Schedule, Class]), CourseModule, DepartmentModule, InstructorModule, MeetingTimeModule, RoomModule, ], providers: [ScheduleService, ScheduleRepository, Data, GeneticAlgorithm], controllers: [ScheduleController], }) export class ScheduleModule {}
原理说明
NestJS的依赖注入系统适用于需要复用、生命周期由框架管控的服务类。像Population这种需要动态参数才能创建实例的类,应该通过手动new的方式创建,而非交给依赖注入管理。移除@Injectable()和providers中的注册后,Nest不再尝试解析它的依赖,错误即可解决。
内容的提问来源于stack exchange,提问作者engineerdavut
相关产品推荐
相关产品推荐

