记录一次Prism9隐式注册引发的事件聚合器失效问题

直接上代码 1、我的注册从App的RegisterTypes方法迁移到了模块

arduino 复制代码
 public class AccountModule : IModule
 {
     public void OnInitialized(IContainerProvider containerProvider)
     {
     }

     public void RegisterTypes(IContainerRegistry containerRegistry)
     {
         containerRegistry.RegisterSingleton<LoginAccount>();
     }
 }

虽然我是立即执行的引用模块

csharp 复制代码
 protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
 {
     Logger.WriteLocal("开始加载dll");
     Assembly.LoadFrom(@"Music.Core.dll");
     Logger.WriteLocal("开始加载模块");
     moduleCatalog.AddModule<AccountModule>(InitializationMode.WhenAvailable);

     var m = moduleCatalog.Modules.First(me => me.ModuleName == nameof(AccountModule));
     Logger.WriteLocal($"🔍 模块 {m.ModuleName} 状态 = {m.State}");
 }

但是log显示NotStarted 我虽然登录的时候写了

csharp 复制代码
 public class LoginWindowViewModel : BindableBase
 {
     private readonly LoginAccount _loginAccount;

     public LoginWindowViewModel(IEventAggregator eventAggregator, LoginAccount loginAccount)
     {
         _eventAggregator = eventAggregator;
         LoginCommand = new DelegateCommand<Window>(ExecuteLogin);

     }

     private IEventAggregator _eventAggregator;

     private void ExecuteLogin(Window window)
     {
         _logger.WriteLocal("🚀 准备发布 LoginEvent");
         _eventAggregator.GetEvent<LoginEvent>().Publish(window);
     }

     public ICommand LoginCommand { get; set; }
 }

但是事件聚合器

csharp 复制代码
 public class LoginAccount
 {
     private readonly IEventAggregator _eventAggregator;
     private ITangdaoLogger _logger = TangdaoLogger.Get(typeof(LoginAccount));

     public LoginAccount(IEventAggregator eventAggregator)
     {
         _eventAggregator = eventAggregator;
         var token = _eventAggregator.GetEvent<LoginEvent>().Subscribe(Login);
         _logger.WriteLocal($"✅ LoginAccount 订阅完成,token={token.GetHashCode()}");
     }

     private void Login(Window window)
     {
         window.DialogResult = true;
     }
 }

并没有进入 因为隐式注册的时候LoginAccount的生命周期是短暂的或者没有传递,此时,我改为

ini 复制代码
  private readonly LoginAccount _loginAccount;

  public LoginWindowViewModel(IEventAggregator eventAggregator, LoginAccount loginAccount)
  {
      _eventAggregator = eventAggregator;
       _loginAccount = loginAccount;
      LoginCommand = new DelegateCommand<Window>(ExecuteLogin);
  }

我只是引入了字段,现在成功了 说明 1、可能被GC回收了 2、Prism默认的解析机制,与微软的ServiceCollection不同,ServiceCollection是注册了类才能解析,而Prism具有隐式注册机制,比如程序启动的时候

kotlin 复制代码
 return Container.Resolve<MainWindow>();

我们明明没有对MainWindow进行注册,但是却可以解析出来,而ServiceCollection不可以, 这个隐式注册的生命周期是瞬态的,导致拿到的不是同一个 我继续尝试,使用Rgister注册,结果是只要使用了 _loginAccount=loginAccount成功,不使用失败 那么现在结论只剩下一个了, 我现在将事件聚合器改为强引用

swift 复制代码
_eventAggregator.GetEvent<LoginEvent>().Subscribe(Login, ThreadOption.UIThread, true);

不再使用字段长时间保持生命周期的引用,结果登录成功 我接着尝试,连同构造器的引用去除,结果登录失败,说明虽然不需要写字段,使用了强制引用,但是依然需要在构造器写进对象

java 复制代码
public LoginWindowViewModel(IEventAggregator eventAggregator, LoginAccount loginAccount)

说明

arduino 复制代码
public LoginWindowViewModel(IEventAggregator eventAggregator, LoginAccount loginAccount)
{
    _eventAggregator = eventAggregator;
    
    // 情况A:参数未被使用
    // JIT可能认为loginAccount是栈上的临时变量,方法结束后即可回收
    
    // 情况B:保存到字段
    _loginAccount = loginAccount; // 现在引用进入GC Roots链
}

JIT可能将未使用的参数优化掉 实际的执行代码可能根本不保留这个引用 GC Roots的定义: 静态字段 活动线程的栈帧中的局部变量 CPU寄存器中的引用 实例字段(当实例本身被根引用时) 关键的区别在于

arduino 复制代码
// 栈上引用(可能被提前回收)
public void Method(LoginAccount param)
{
    // param 只在栈上,方法结束后GC可能回收
}

// 实例字段引用(稳定的GC Root)  
public class ViewModel
{
    private LoginAccount _account; // 实例字段,生命周期与ViewModel一致
}
相关推荐
952361 小时前
MyBatis
后端·spring·mybatis
uzong4 小时前
9 种 RAG 架构,每位 AI 开发者必学:完整实战指南
后端
小江的记录本5 小时前
【Kafka核心】架构模型:Producer、Broker、Consumer、Consumer Group、Topic、Partition、Replica
java·数据库·分布式·后端·搜索引擎·架构·kafka
止语Lab5 小时前
从手动到框架:Go DI 演进的三个拐点
开发语言·后端·golang
Daybreak7 小时前
Elasticsearch 里的索引和 Mapping,到底是什么关系?
后端
Lee川7 小时前
Prisma 实战指南:像搭积木一样设计古诗词数据库
前端·数据库·后端
李小狼lee8 小时前
深入浅出sse协议,用代码自己实现
后端
SamDeepThinking8 小时前
并发量就算只有2,该上锁还得上呀
java·后端·架构