详细讲解 + 结合您项目的最佳实践完整代码)
✅ 依赖注入Dependency Injection, DI详细讲解 结合您项目的最佳实践完整代码一、什么是依赖注入DI依赖注入是一种软件设计模式属于控制反转IoC的具体实现。核心思想不要在类内部自己创建依赖的对象而是通过外部容器把依赖“注入”进来。传统方式紧耦合publicclassMainBoardService{privateIStationRepository_reponewStationRepository();// 自己 new}DI 方式松耦合publicclassMainBoardService{privatereadonlyIStationRepository_repo;publicMainBoardService(IStationRepositoryrepo)// 通过构造函数注入{_reporepo;}}二、依赖注入的三大核心方式注入方式代码示例使用场景推荐程度构造函数注入推荐public XX(IYY yy)必须依赖、不可变★★★★★属性注入public IYY Yy { get; set; }可选依赖★★方法注入public void Init(IYY yy)临时使用或后期注入★三、依赖注入的重大优势松耦合类与类之间通过接口依赖便于替换实现。可测试性单元测试时可轻松注入 Mock 对象。可维护性修改实现不需要改动调用方。生命周期管理容器自动管理 Singleton、Scoped、Transient。并行开发团队成员可并行开发不同模块。配置集中所有依赖注册统一管理清晰可见。支持 AOP日志、事务、缓存等横切关注点。四、您项目中用到的两种容器Microsoft.Extensions.DependencyInjectionMS DI轻量、官方、性能好用于 EF Core。Prism.UnityWPF/Prism 框架的 IoC 容器用于 UI 层和服务解析。当前问题根源两种容器混合使用时必须做好“桥接”。五、优化后的完整代码推荐最终版本1.App.xaml.cs最重要// MaxWell/App.xaml.csusinglog4net;usingMaxWell.CommonBasis;usingMaxWell.Interface;usingMicrosoft.EntityFrameworkCore;usingMicrosoft.Extensions.DependencyInjection;usingPrism.Ioc;usingPrism.Unity;usingSystem;usingSystem.Threading;usingSystem.Threading.Tasks;usingSystem.Windows;namespaceMaxWell{publicpartialclassApp:PrismApplication{privateIServiceProvider_msServiceProvidernull!;// MS DI 容器publicApp(){AppDomain.CurrentDomain.UnhandledException(s,e)LogUnhandledException(e.ExceptionObjectasException,AppDomain);DispatcherUnhandledException(s,e)LogUnhandledException(e.Exception,Dispatcher);TaskScheduler.UnobservedTaskException(s,e)LogUnhandledException(e.Exception,TaskScheduler);}protectedoverrideWindowCreateShell()Container.ResolveMainWindow();protectedoverridevoidRegisterTypes(IContainerRegistrycontainerRegistry){// 1. 配置 Microsoft DI主要负责 EF Core 和仓储varservicesnewServiceCollection();ConfigureMicrosoftServices(services);_msServiceProviderservices.BuildServiceProvider();containerRegistry.RegisterInstance(_msServiceProvider);// 2. 桥接 MS DI 到 Prism 容器关键containerRegistry.RegisterSingletonIStationRepository(sp_msServiceProvider.GetRequiredServiceIStationRepository());// 3. Prism 容器注册UI 业务服务ConfigurePrismServices(containerRegistry);}privatevoidConfigureMicrosoftServices(IServiceCollectionservices){varconnectionStringData Sourcemaxwell.db;services.AddDbContextAppDbContext(optionsoptions.UseSqlite(connectionString),ServiceLifetime.Scoped);services.AddScopedIStationRepository,StationRepository();services.AddSingletonRepositoryFactory();}privatevoidConfigurePrismServices(IContainerRegistrycontainerRegistry){containerRegistry.RegisterSingletonIAlarmQueue,AlarmQueue();containerRegistry.RegisterSingletonStationManager();containerRegistry.RegisterSingletonIServiceFactory,ServiceFactory();// 视图与 ViewModelcontainerRegistry.RegisterForNavigationMainWindow,MainViewModel(MainWindow);}protectedoverrideasyncvoidOnInitialized(){base.OnInitialized();try{// 初始化数据库usingvarscope_msServiceProvider.CreateScope();vardbscope.ServiceProvider.GetRequiredServiceAppDbContext();awaitdb.Database.EnsureCreatedAsync();// 系统业务初始化awaitAppInitializer.InitializeAsync(Container);}catch(Exceptionex){MessageBox.Show($系统初始化失败{ex.Message}\n\n{ex},严重错误,MessageBoxButton.OK,MessageBoxImage.Error);Shutdown();}}protectedoverrideasyncvoidOnExit(ExitEventArgse){awaitAppInitializer.UninitializeAsync();(_msServiceProviderasIDisposable)?.Dispose();base.OnExit(e);}privatevoidLogUnhandledException(Exception?ex,stringsource){LogManager.GetLogger(GlobalException).Fatal($[{source}] 未捕获异常,ex);}}}2.ServiceFactory.cs// MaxWell.CommonBasis/ServiceFactory.csusingMaxWell.Common;usingMaxWell.Interface;usingMaxWell.Model;usingMaxWell.Service;namespaceMaxWell.CommonBasis{publicinterfaceIServiceFactory{IMainBoardServiceCreateMainBoardService(stringstationId,HardwareDevicehardwareDevice);IAuxCtrlServiceCreateAuxCtrlService(stringstationId,HardwareDevicehardwareDevice);ILoadMonitorServiceCreateLoadMonitorService(stringstationId,HardwareDevicehardwareDevice);IRFIDServiceCreateRFIDService(stringstationId,HardwareDevicehardwareDevice);IScannerServiceCreateScannerService(stringstationId,HardwareDevicehardwareDevice);}publicclassServiceFactory:IServiceFactory{privatereadonlyIStationRepository_repository;privatereadonlyIAlarmQueue_alarmQueue;// 构造函数注入推荐方式publicServiceFactory(IStationRepositoryrepository,IAlarmQueuealarmQueue){_repositoryrepository??thrownewArgumentNullException(nameof(repository));_alarmQueuealarmQueue??thrownewArgumentNullException(nameof(alarmQueue));}publicIMainBoardServiceCreateMainBoardService(stringstationId,HardwareDevicehardwareDevice)newMainBoardService(Registry.CreateDriver(hardwareDevice.DriverType??MainBoard,stationId),_repository,_alarmQueue,stationId,hardwareDevice);// 其他 Create 方法同理...publicIAuxCtrlServiceCreateAuxCtrlService(stringstationId,HardwareDevicehardwareDevice)newAuxCtrlBoardService(Registry.CreateDriver(hardwareDevice.DriverType??AuxPLC,stationId),_repository,_alarmQueue,stationId,hardwareDevice);publicILoadMonitorServiceCreateLoadMonitorService(stringstationId,HardwareDevicehardwareDevice)newLoadMonitorService(Registry.CreateDriver(hardwareDevice.DriverType??LoadMonitor,stationId),_repository,_alarmQueue,stationId,hardwareDevice);publicIRFIDServiceCreateRFIDService(stringstationId,HardwareDevicehardwareDevice)newRFIDService(Registry.CreateDriver(hardwareDevice.DriverType??RFID,stationId),_repository,_alarmQueue,stationId,hardwareDevice);publicIScannerServiceCreateScannerService(stringstationId,HardwareDevicehardwareDevice)newScannerService(Registry.CreateDriver(hardwareDevice.DriverType??Scanner,stationId),_repository,_alarmQueue,stationId,hardwareDevice);}}3.HardwareServiceBase.cs关键基类建议这样写publicabstractclassHardwareServiceBase:IHardwareService{protectedreadonlyIHardwareDriver_driver;protectedreadonlyIStationRepository_repository;protectedreadonlyIAlarmQueue_alarmQueue;protectedreadonlyILog_logger;protectedreadonlystringStationId;protectedreadonlystringServiceName;protectedHardwareServiceBase(IHardwareDriverdriver,IStationRepositoryrepository,IAlarmQueuealarmQueue,stringstationId,stringserviceName){_driverdriver??thrownewArgumentNullException(nameof(driver));_repositoryrepository??thrownewArgumentNullException(nameof(repository));_alarmQueuealarmQueue??thrownewArgumentNullException(nameof(alarmQueue));StationIdstationId;ServiceNameserviceName;_loggerLogManager.GetLogger($Service.{serviceName});}// ... 其他方法保持不变InitializeAsync、StartAsync 等}六、总结建议优先使用构造函数注入。接口编程所有服务都依赖接口而非具体类。避免 Service Locator 模式Container.Resolve滥用。生命周期选择Singleton全局唯一如StationManager、ServiceFactoryScoped每个请求/作用域一个如DbContext、仓储Transient每次都新创建